From nobody Mon Feb 9 17:05:14 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1A7F2FB630; Wed, 22 Oct 2025 07:40:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761118824; cv=none; b=QlhzkCmVAzPkEiKY5S8Dm4MM+Tknyf8eW9E3zHhdWq1D86O9lvPfiTLSdxeYyO4uOijSbY/EWf70Pm7SqFT2zPBq29zfK1NxpcdfrgrkArmF4SFvnQ3kNno0picQwNAbzqC5FtXnBY+Fr2AMRj7HMQTJ3Dlbxx3fRJvyYrSKKmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761118824; c=relaxed/simple; bh=rVKQOSpNXEzI6wGszsrM1qMvHuv7XN9D2gQugG+pQtk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dinoErulKnnOyDBM2UQvzU7JPNgatLzCvOLt3DJt9OOPcjLgzimbErmN5MfplCcuVn8QXHxtlfjKpfwbC0Wubt6IfZ7tM7syKmZo+oRKlB1u2odSJW4T3HZ5bAdFJOy30nFEsWjhsFZkNMmIVZ1j9+3NoX3Ak+amj8gHs47hKz0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=AN/BRf1m; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="AN/BRf1m" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 4B1D34E41276; Wed, 22 Oct 2025 07:40:21 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 20680606DC; Wed, 22 Oct 2025 07:40:21 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C82D4102F2429; Wed, 22 Oct 2025 09:40:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1761118819; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=9elYQCBvjDoWqk97ClXQKLrv+rKMW91Qg0RC83oLLzQ=; b=AN/BRf1mBUnNsUj0e72hmsjVysTAF6CZCTPx5ApBwRzkAqVV2Wd1r/zoM0IS7Ecmr/uMSF trmBFm63+uM9hlrmu7m//vfYWnqM0KirdEzZw+QkXCtPt84ZuduRf3Bw2pQKeF0dTrHRKX 560eUPdHMcJCH8vBjvSrsJYJDHYksHLBE3O2bNHpxKiYwa0ex+1EfFwONY0hZqO26jyRwV XNuShl0I7ulZ3Qu/IhgFLMEuNG0ok3C0KIGlivb5zIydDDueFFVtCvWHePruku/oH70Vpf tguwH+VAK6KuEo+zYFMQHBWi+Q8CzVkA/ykyoYtCE3hlLc4nkKkbp7P5YZOx/g== From: =?utf-8?q?Alexis_Lothor=C3=A9_=28eBPF_Foundation=29?= Date: Wed, 22 Oct 2025 09:39:50 +0200 Subject: [PATCH bpf-next v2 1/4] selftests/bpf: add tc helpers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251022-tc_tunnel-v2-1-a44a0bd52902@bootlin.com> References: <20251022-tc_tunnel-v2-0-a44a0bd52902@bootlin.com> In-Reply-To: <20251022-tc_tunnel-v2-0-a44a0bd52902@bootlin.com> To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan Cc: ebpf@linuxfoundation.org, Thomas Petazzoni , Bastien Curutchet , bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?Alexis_Lothor=C3=A9_=28eBPF_Foundation=29?= X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 The test_tunnel.c file defines small fonctions to easily attach eBPF programs to tc hooks, either on egress, ingress or both. Create a shared helper in network_helpers.c so that other tests can benefit from it. Signed-off-by: Alexis Lothor=C3=A9 (eBPF Foundation) --- Changes in v2: - declare new TC API in network_helpers instead of a dedicated file - only declare tc_prog_attach, not the intermediate "generic_attachigr_fd/egr_fd - pass an interface name rather than an interface id - update accordingly test_tunnel.c --- tools/testing/selftests/bpf/network_helpers.c | 45 +++++++++ tools/testing/selftests/bpf/network_helpers.h | 16 +++ .../testing/selftests/bpf/prog_tests/test_tunnel.c | 107 +++--------------= ---- 3 files changed, 75 insertions(+), 93 deletions(-) diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/= selftests/bpf/network_helpers.c index cdf7b6641444..0998d71fe57a 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -766,6 +766,51 @@ int send_recv_data(int lfd, int fd, uint32_t total_byt= es) return err; } =20 +int tc_prog_attach(const char *dev, int ingress_fd, int egress_fd) +{ + int ifindex; + + if (!ASSERT_TRUE(ingress_fd >=3D 0 || egress_fd >=3D 0, + "at least one program fd is valid")) + return -1; + + ifindex =3D if_nametoindex(dev); + if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) + return -1; + + DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex =3D ifindex, + .attach_point =3D BPF_TC_INGRESS | BPF_TC_EGRESS); + DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle =3D 1, + .priority =3D 1, .prog_fd =3D ingress_fd); + DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle =3D 1, + .priority =3D 1, .prog_fd =3D egress_fd); + int ret; + + ret =3D bpf_tc_hook_create(&hook); + if (!ASSERT_OK(ret, "create tc hook")) + return ret; + + if (ingress_fd >=3D 0) { + hook.attach_point =3D BPF_TC_INGRESS; + ret =3D bpf_tc_attach(&hook, &opts1); + if (!ASSERT_OK(ret, "bpf_tc_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + } + + if (egress_fd >=3D 0) { + hook.attach_point =3D BPF_TC_EGRESS; + ret =3D bpf_tc_attach(&hook, &opts2); + if (!ASSERT_OK(ret, "bpf_tc_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + } + + return 0; +} + #ifdef TRAFFIC_MONITOR struct tmonitor_ctx { pcap_t *pcap; diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/= selftests/bpf/network_helpers.h index ef208eefd571..79a010c88e11 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -255,6 +255,22 @@ struct tmonitor_ctx; =20 typedef int (*tm_print_fn_t)(const char *format, va_list args); =20 +/** + * tc_prog_attach - attach BPF program(s) to an interface + * + * Takes file descriptors pointing to at least one, at most two BPF + * programs, and attach those programs to an interface ingress, egress or + * both. + * + * @dev: string containing the interface name + * @ingress_fd: file descriptor of the program to attach to interface ingr= ess + * @egress_fd: file descriptor of the program to attach to interface egress + * + * Returns 0 on success, -1 if no valid file descriptor has been found, if + * the interface name is invalid or if an error ocurred during attach. + */ +int tc_prog_attach(const char *dev, int ingress_fd, int egress_fd); + #ifdef TRAFFIC_MONITOR struct tmonitor_ctx *traffic_monitor_start(const char *netns, const char *= test_name, const char *subtest_name); diff --git a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c b/tools/t= esting/selftests/bpf/prog_tests/test_tunnel.c index bae0e9de277d..eb9309931272 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c +++ b/tools/testing/selftests/bpf/prog_tests/test_tunnel.c @@ -534,85 +534,6 @@ static void ping6_dev1(void) close_netns(nstoken); } =20 -static int attach_tc_prog(int ifindex, int igr_fd, int egr_fd) -{ - DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex =3D ifindex, - .attach_point =3D BPF_TC_INGRESS | BPF_TC_EGRESS); - DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle =3D 1, - .priority =3D 1, .prog_fd =3D igr_fd); - DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle =3D 1, - .priority =3D 1, .prog_fd =3D egr_fd); - int ret; - - ret =3D bpf_tc_hook_create(&hook); - if (!ASSERT_OK(ret, "create tc hook")) - return ret; - - if (igr_fd >=3D 0) { - hook.attach_point =3D BPF_TC_INGRESS; - ret =3D bpf_tc_attach(&hook, &opts1); - if (!ASSERT_OK(ret, "bpf_tc_attach")) { - bpf_tc_hook_destroy(&hook); - return ret; - } - } - - if (egr_fd >=3D 0) { - hook.attach_point =3D BPF_TC_EGRESS; - ret =3D bpf_tc_attach(&hook, &opts2); - if (!ASSERT_OK(ret, "bpf_tc_attach")) { - bpf_tc_hook_destroy(&hook); - return ret; - } - } - - return 0; -} - -static int generic_attach(const char *dev, int igr_fd, int egr_fd) -{ - int ifindex; - - if (!ASSERT_OK_FD(igr_fd, "check ingress fd")) - return -1; - if (!ASSERT_OK_FD(egr_fd, "check egress fd")) - return -1; - - ifindex =3D if_nametoindex(dev); - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) - return -1; - - return attach_tc_prog(ifindex, igr_fd, egr_fd); -} - -static int generic_attach_igr(const char *dev, int igr_fd) -{ - int ifindex; - - if (!ASSERT_OK_FD(igr_fd, "check ingress fd")) - return -1; - - ifindex =3D if_nametoindex(dev); - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) - return -1; - - return attach_tc_prog(ifindex, igr_fd, -1); -} - -static int generic_attach_egr(const char *dev, int egr_fd) -{ - int ifindex; - - if (!ASSERT_OK_FD(egr_fd, "check egress fd")) - return -1; - - ifindex =3D if_nametoindex(dev); - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) - return -1; - - return attach_tc_prog(ifindex, -1, egr_fd); -} - static void test_vxlan_tunnel(void) { struct test_tunnel_kern *skel =3D NULL; @@ -635,12 +556,12 @@ static void test_vxlan_tunnel(void) goto done; get_src_prog_fd =3D bpf_program__fd(skel->progs.vxlan_get_tunnel_src); set_src_prog_fd =3D bpf_program__fd(skel->progs.vxlan_set_tunnel_src); - if (generic_attach(VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) + if (tc_prog_attach(VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) goto done; =20 /* load and attach bpf prog to veth dev tc hook point */ set_dst_prog_fd =3D bpf_program__fd(skel->progs.veth_set_outer_dst); - if (generic_attach_igr("veth1", set_dst_prog_fd)) + if (tc_prog_attach("veth1", set_dst_prog_fd, -1)) goto done; =20 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ @@ -648,7 +569,7 @@ static void test_vxlan_tunnel(void) if (!ASSERT_OK_PTR(nstoken, "setns src")) goto done; set_dst_prog_fd =3D bpf_program__fd(skel->progs.vxlan_set_tunnel_dst); - if (generic_attach_egr(VXLAN_TUNL_DEV0, set_dst_prog_fd)) + if (tc_prog_attach(VXLAN_TUNL_DEV0, -1, set_dst_prog_fd)) goto done; close_netns(nstoken); =20 @@ -695,7 +616,7 @@ static void test_ip6vxlan_tunnel(void) goto done; get_src_prog_fd =3D bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src); set_src_prog_fd =3D bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src); - if (generic_attach(IP6VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) + if (tc_prog_attach(IP6VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) goto done; =20 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ @@ -703,7 +624,7 @@ static void test_ip6vxlan_tunnel(void) if (!ASSERT_OK_PTR(nstoken, "setns src")) goto done; set_dst_prog_fd =3D bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst); - if (generic_attach_egr(IP6VXLAN_TUNL_DEV0, set_dst_prog_fd)) + if (tc_prog_attach(IP6VXLAN_TUNL_DEV0, -1, set_dst_prog_fd)) goto done; close_netns(nstoken); =20 @@ -764,7 +685,7 @@ static void test_ipip_tunnel(enum ipip_encap encap) skel->progs.ipip_set_tunnel); } =20 - if (generic_attach(IPIP_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) + if (tc_prog_attach(IPIP_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) goto done; =20 ping_dev0(); @@ -797,7 +718,7 @@ static void test_xfrm_tunnel(void) =20 /* attach tc prog to tunnel dev */ tc_prog_fd =3D bpf_program__fd(skel->progs.xfrm_get_state); - if (generic_attach_igr("veth1", tc_prog_fd)) + if (tc_prog_attach("veth1", tc_prog_fd, -1)) goto done; =20 /* attach xdp prog to tunnel dev */ @@ -870,7 +791,7 @@ static void test_gre_tunnel(enum gre_test test) if (!ASSERT_OK(err, "add tunnel")) goto done; =20 - if (generic_attach(GRE_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(GRE_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping_dev0(); @@ -911,7 +832,7 @@ static void test_ip6gre_tunnel(enum ip6gre_test test) =20 set_fd =3D bpf_program__fd(skel->progs.ip6gretap_set_tunnel); get_fd =3D bpf_program__fd(skel->progs.ip6gretap_get_tunnel); - if (generic_attach(IP6GRE_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(IP6GRE_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping6_veth0(); @@ -954,7 +875,7 @@ static void test_erspan_tunnel(enum erspan_test test) =20 set_fd =3D bpf_program__fd(skel->progs.erspan_set_tunnel); get_fd =3D bpf_program__fd(skel->progs.erspan_get_tunnel); - if (generic_attach(ERSPAN_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(ERSPAN_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping_dev0(); @@ -990,7 +911,7 @@ static void test_ip6erspan_tunnel(enum erspan_test test) =20 set_fd =3D bpf_program__fd(skel->progs.ip4ip6erspan_set_tunnel); get_fd =3D bpf_program__fd(skel->progs.ip4ip6erspan_get_tunnel); - if (generic_attach(IP6ERSPAN_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(IP6ERSPAN_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping6_veth0(); @@ -1017,7 +938,7 @@ static void test_geneve_tunnel(void) =20 set_fd =3D bpf_program__fd(skel->progs.geneve_set_tunnel); get_fd =3D bpf_program__fd(skel->progs.geneve_get_tunnel); - if (generic_attach(GENEVE_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(GENEVE_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping_dev0(); @@ -1044,7 +965,7 @@ static void test_ip6geneve_tunnel(void) =20 set_fd =3D bpf_program__fd(skel->progs.ip6geneve_set_tunnel); get_fd =3D bpf_program__fd(skel->progs.ip6geneve_get_tunnel); - if (generic_attach(IP6GENEVE_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(IP6GENEVE_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping_dev0(); @@ -1083,7 +1004,7 @@ static void test_ip6tnl_tunnel(enum ip6tnl_test test) get_fd =3D bpf_program__fd(skel->progs.ip6ip6_get_tunnel); break; } - if (generic_attach(IP6TNL_TUNL_DEV1, get_fd, set_fd)) + if (tc_prog_attach(IP6TNL_TUNL_DEV1, get_fd, set_fd)) goto done; =20 ping6_veth0(); --=20 2.51.1.dirty