From: Mahe Tardy <mahe.tardy@gmail.com>
To: mahe.tardy@gmail.com
Cc: alexei.starovoitov@gmail.com, andrii@kernel.org, ast@kernel.org,
bpf@vger.kernel.org, coreteam@netfilter.org,
daniel@iogearbox.net, fw@strlen.de, john.fastabend@gmail.com,
lkp@intel.com, martin.lau@linux.dev, netdev@vger.kernel.org,
netfilter-devel@vger.kernel.org, oe-kbuild-all@lists.linux.dev,
pablo@netfilter.org
Subject: [PATCH bpf-next v4 5/6] selftests/bpf: add icmp_send_unreach kfunc IPv6 tests
Date: Mon, 20 Apr 2026 10:58:15 +0000 [thread overview]
Message-ID: <20260420105816.72168-6-mahe.tardy@gmail.com> (raw)
In-Reply-To: <20260420105816.72168-1-mahe.tardy@gmail.com>
This test extend the existing IPv4 tests to IPv6.
Note that we need to set IP_RECVERR on the socket for IPv6 in
connect_to_fd_nonblock otherwise the error will be ignored even if we
are in the middle of the TCP handshake. See in
net/ipv6/datagram.c:ipv6_icmp_error line 313 for more details.
Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
---
.../bpf/prog_tests/icmp_send_unreach_kfunc.c | 83 ++++++++++++-------
.../selftests/bpf/progs/icmp_send_unreach.c | 46 ++++++++--
2 files changed, 93 insertions(+), 36 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/icmp_send_unreach_kfunc.c b/tools/testing/selftests/bpf/prog_tests/icmp_send_unreach_kfunc.c
index 24d5e01cfe80..047bfd4d80f7 100644
--- a/tools/testing/selftests/bpf/prog_tests/icmp_send_unreach_kfunc.c
+++ b/tools/testing/selftests/bpf/prog_tests/icmp_send_unreach_kfunc.c
@@ -8,15 +8,17 @@
#define SRV_PORT 54321
#define ICMP_DEST_UNREACH 3
+#define ICMPV6_DEST_UNREACH 1
#define ICMP_FRAG_NEEDED 4
#define NR_ICMP_UNREACH 15
+#define NR_ICMPV6_UNREACH 6
static int connect_to_fd_nonblock(int server_fd)
{
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
- int fd, err;
+ int fd, err, on = 1;
if (getsockname(server_fd, (struct sockaddr *)&addr, &len))
return -1;
@@ -25,6 +27,12 @@ static int connect_to_fd_nonblock(int server_fd)
if (fd < 0)
return -1;
+ if (addr.ss_family == AF_INET6 &&
+ setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &on, sizeof(on)) < 0) {
+ close(fd);
+ return -1;
+ }
+
err = connect(fd, (struct sockaddr *)&addr, len);
if (err < 0 && errno != EINPROGRESS) {
close(fd);
@@ -34,7 +42,7 @@ static int connect_to_fd_nonblock(int server_fd)
return fd;
}
-static void read_icmp_errqueue(int sockfd, int expected_code)
+static void read_icmp_errqueue(int sockfd, int expected_code, int af)
{
ssize_t n;
struct sock_extended_err *sock_err;
@@ -44,6 +52,12 @@ static void read_icmp_errqueue(int sockfd, int expected_code)
.msg_control = ctrl_buf,
.msg_controllen = sizeof(ctrl_buf),
};
+ int expected_level = (af == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
+ int expected_type = (af == AF_INET) ? IP_RECVERR : IPV6_RECVERR;
+ int expected_origin = (af == AF_INET) ? SO_EE_ORIGIN_ICMP :
+ SO_EE_ORIGIN_ICMP6;
+ int expected_ee_type = (af == AF_INET) ? ICMP_DEST_UNREACH :
+ ICMPV6_DEST_UNREACH;
n = recvmsg(sockfd, &msg, MSG_ERRQUEUE);
if (!ASSERT_GE(n, 0, "recvmsg_errqueue"))
@@ -54,28 +68,27 @@ static void read_icmp_errqueue(int sockfd, int expected_code)
return;
for (; cm; cm = CMSG_NXTHDR(&msg, cm)) {
- if (!ASSERT_EQ(cm->cmsg_level, IPPROTO_IP, "cmsg_type") ||
- !ASSERT_EQ(cm->cmsg_type, IP_RECVERR, "cmsg_level"))
+ if (!ASSERT_EQ(cm->cmsg_level, expected_level, "cmsg_level") ||
+ !ASSERT_EQ(cm->cmsg_type, expected_type, "cmsg_type"))
continue;
sock_err = (struct sock_extended_err *)CMSG_DATA(cm);
- if (!ASSERT_EQ(sock_err->ee_origin, SO_EE_ORIGIN_ICMP,
- "sock_err_origin_icmp"))
+ if (!ASSERT_EQ(sock_err->ee_origin, expected_origin,
+ "sock_err_origin"))
return;
- if (!ASSERT_EQ(sock_err->ee_type, ICMP_DEST_UNREACH,
+ if (!ASSERT_EQ(sock_err->ee_type, expected_ee_type,
"sock_err_type_dest_unreach"))
return;
ASSERT_EQ(sock_err->ee_code, expected_code, "sock_err_code");
}
}
-static void trigger_prog_read_icmp_errqueue(int *code)
+static void trigger_prog_read_icmp_errqueue(int *code, int af, const char *addr)
{
int srv_fd = -1, client_fd = -1;
- srv_fd = start_server(AF_INET, SOCK_STREAM, "127.0.0.1", SRV_PORT,
- TIMEOUT_MS);
+ srv_fd = start_server(af, SOCK_STREAM, addr, SRV_PORT, TIMEOUT_MS);
if (!ASSERT_GE(srv_fd, 0, "start_server"))
return;
@@ -86,18 +99,40 @@ static void trigger_prog_read_icmp_errqueue(int *code)
}
/* Skip reading ICMP error queue if code is invalid */
- if (*code >= 0 && *code <= NR_ICMP_UNREACH)
- read_icmp_errqueue(client_fd, *code);
+ if (*code >= 0 && ((af == AF_INET && *code <= NR_ICMP_UNREACH) ||
+ (af == AF_INET6 && *code <= NR_ICMPV6_UNREACH)))
+ read_icmp_errqueue(client_fd, *code, af);
- close(srv_fd);
close(client_fd);
+ close(srv_fd);
+}
+
+static void run_icmp_test(struct icmp_send_unreach *skel, int af,
+ const char *addr, int max_code)
+{
+ int *code = &skel->bss->unreach_code;
+
+ for (*code = 0; *code <= max_code; (*code)++) {
+ /* The TCP stack reacts differently when asking for
+ * fragmentation, let's ignore it for now.
+ */
+ if (af == AF_INET && *code == ICMP_FRAG_NEEDED)
+ continue;
+
+ trigger_prog_read_icmp_errqueue(code, af, addr);
+ ASSERT_EQ(skel->data->kfunc_ret, 0, "kfunc_ret");
+ }
+
+ /* Test an invalid code */
+ *code = -1;
+ trigger_prog_read_icmp_errqueue(code, af, addr);
+ ASSERT_EQ(skel->data->kfunc_ret, -EINVAL, "kfunc_ret");
}
void test_icmp_send_unreach_kfunc(void)
{
struct icmp_send_unreach *skel;
int cgroup_fd = -1;
- int *code;
skel = icmp_send_unreach__open_and_load();
if (!ASSERT_OK_PTR(skel, "skel_open"))
@@ -112,23 +147,11 @@ void test_icmp_send_unreach_kfunc(void)
if (!ASSERT_OK_PTR(skel->links.egress, "prog_attach_cgroup"))
goto cleanup;
- code = &skel->bss->unreach_code;
-
- for (*code = 0; *code <= NR_ICMP_UNREACH; (*code)++) {
- /* The TCP stack reacts differently when asking for
- * fragmentation, let's ignore it for now.
- */
- if (*code == ICMP_FRAG_NEEDED)
- continue;
-
- trigger_prog_read_icmp_errqueue(code);
- ASSERT_EQ(skel->data->kfunc_ret, 0, "kfunc_ret");
- }
+ if (test__start_subtest("ipv4"))
+ run_icmp_test(skel, AF_INET, "127.0.0.1", NR_ICMP_UNREACH);
- /* Test an invalid code */
- *code = -1;
- trigger_prog_read_icmp_errqueue(code);
- ASSERT_EQ(skel->data->kfunc_ret, -EINVAL, "kfunc_ret");
+ if (test__start_subtest("ipv6"))
+ run_icmp_test(skel, AF_INET6, "::1", NR_ICMPV6_UNREACH);
cleanup:
icmp_send_unreach__destroy(skel);
diff --git a/tools/testing/selftests/bpf/progs/icmp_send_unreach.c b/tools/testing/selftests/bpf/progs/icmp_send_unreach.c
index 6fc5595f08aa..112b9cbfab6f 100644
--- a/tools/testing/selftests/bpf/progs/icmp_send_unreach.c
+++ b/tools/testing/selftests/bpf/progs/icmp_send_unreach.c
@@ -6,6 +6,11 @@
#define SERVER_PORT 54321
/* 127.0.0.1 in network byte order */
#define SERVER_IP 0x7F000001
+/* ::1 in network byte order */
+#define SERVER_IP6_0 0x00000000
+#define SERVER_IP6_1 0x00000000
+#define SERVER_IP6_2 0x00000000
+#define SERVER_IP6_3 0x01000000
int unreach_code = 0;
int kfunc_ret = -1;
@@ -16,17 +21,46 @@ int egress(struct __sk_buff *skb)
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct iphdr *iph;
+ struct ipv6hdr *ip6h;
struct tcphdr *tcph;
+ __u8 version;
- iph = data;
- if ((void *)(iph + 1) > data_end || iph->version != 4 ||
- iph->protocol != IPPROTO_TCP || iph->daddr != bpf_htonl(SERVER_IP))
+ if (data + 1 > data_end)
return SK_PASS;
- tcph = (void *)iph + iph->ihl * 4;
- if ((void *)(tcph + 1) > data_end ||
- tcph->dest != bpf_htons(SERVER_PORT))
+ version = (*((__u8 *)data)) >> 4;
+
+ if (version == 4) {
+ iph = data;
+ if ((void *)(iph + 1) > data_end ||
+ iph->protocol != IPPROTO_TCP ||
+ iph->daddr != bpf_htonl(SERVER_IP))
+ return SK_PASS;
+
+ tcph = (void *)iph + iph->ihl * 4;
+ if ((void *)(tcph + 1) > data_end ||
+ tcph->dest != bpf_htons(SERVER_PORT))
+ return SK_PASS;
+
+ } else if (version == 6) {
+ ip6h = data;
+ if ((void *)(ip6h + 1) > data_end ||
+ ip6h->nexthdr != IPPROTO_TCP)
+ return SK_PASS;
+
+ if (ip6h->daddr.in6_u.u6_addr32[0] != SERVER_IP6_0 ||
+ ip6h->daddr.in6_u.u6_addr32[1] != SERVER_IP6_1 ||
+ ip6h->daddr.in6_u.u6_addr32[2] != SERVER_IP6_2 ||
+ ip6h->daddr.in6_u.u6_addr32[3] != SERVER_IP6_3)
+ return SK_PASS;
+
+ tcph = (void *)(ip6h + 1);
+ if ((void *)(tcph + 1) > data_end ||
+ tcph->dest != bpf_htons(SERVER_PORT))
+ return SK_PASS;
+ } else {
return SK_PASS;
+ }
kfunc_ret = bpf_icmp_send_unreach(skb, unreach_code);
--
2.34.1
next prev parent reply other threads:[~2026-04-20 10:58 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CAADnVQKq_-=N7eJoup6AqFngoocT+D02NF0md_3mi2Vcrw09nQ@mail.gmail.com>
2025-07-25 18:53 ` [PATCH bpf-next v1 0/4] bpf: add icmp_send_unreach kfunc Mahe Tardy
2025-07-25 18:53 ` [PATCH bpf-next v2 1/4] net: move netfilter nf_reject_fill_skb_dst to core ipv4 Mahe Tardy
2025-07-25 18:53 ` [PATCH bpf-next v2 2/4] net: move netfilter nf_reject6_fill_skb_dst to core ipv6 Mahe Tardy
2025-07-25 18:53 ` [PATCH bpf-next v2 3/4] bpf: add bpf_icmp_send_unreach cgroup_skb kfunc Mahe Tardy
2025-07-27 1:49 ` kernel test robot
2025-07-28 9:43 ` [PATCH bpf-next v3 0/4] bpf: add icmp_send_unreach kfunc Mahe Tardy
2025-07-28 9:43 ` [PATCH bpf-next v3 1/4] net: move netfilter nf_reject_fill_skb_dst to core ipv4 Mahe Tardy
2025-07-28 9:43 ` [PATCH bpf-next v3 2/4] net: move netfilter nf_reject6_fill_skb_dst to core ipv6 Mahe Tardy
2025-07-28 9:43 ` [PATCH bpf-next v3 3/4] bpf: add bpf_icmp_send_unreach cgroup_skb kfunc Mahe Tardy
2025-07-28 20:10 ` kernel test robot
2025-07-29 1:05 ` Martin KaFai Lau
2025-07-29 10:06 ` Mahe Tardy
2025-07-29 23:13 ` Martin KaFai Lau
2025-07-28 9:43 ` [PATCH bpf-next v3 4/4] selftests/bpf: add icmp_send_unreach kfunc tests Mahe Tardy
2025-07-28 15:40 ` Yonghong Song
2025-07-28 15:59 ` Mahe Tardy
2025-07-29 1:18 ` Martin KaFai Lau
2025-07-29 9:09 ` Mahe Tardy
2025-07-29 23:27 ` Martin KaFai Lau
2025-07-30 0:01 ` Martin KaFai Lau
2025-07-30 0:32 ` Martin KaFai Lau
2025-08-05 23:26 ` Jordan Rife
2025-07-29 1:21 ` [PATCH bpf-next v3 0/4] bpf: add icmp_send_unreach kfunc Martin KaFai Lau
2025-07-29 9:53 ` Mahe Tardy
2025-07-30 1:54 ` Martin KaFai Lau
2025-08-01 18:50 ` Mahe Tardy
2026-04-20 10:58 ` [PATCH bpf-next v4 0/6] " Mahe Tardy
2026-04-20 10:58 ` [PATCH bpf-next v4 1/6] net: move netfilter nf_reject_fill_skb_dst to core ipv4 Mahe Tardy
2026-04-20 11:36 ` bot+bpf-ci
2026-04-20 13:04 ` Mahe Tardy
2026-04-20 10:58 ` [PATCH bpf-next v4 2/6] net: move netfilter nf_reject6_fill_skb_dst to core ipv6 Mahe Tardy
2026-04-20 10:58 ` [PATCH bpf-next v4 3/6] bpf: add bpf_icmp_send_unreach kfunc Mahe Tardy
2026-04-20 11:36 ` bot+bpf-ci
2026-04-20 13:07 ` Mahe Tardy
2026-04-20 10:58 ` [PATCH bpf-next v4 4/6] selftests/bpf: add icmp_send_unreach kfunc tests Mahe Tardy
2026-04-20 11:36 ` bot+bpf-ci
2026-04-20 13:08 ` Mahe Tardy
2026-04-20 10:58 ` Mahe Tardy [this message]
2026-04-20 10:58 ` [PATCH bpf-next v4 6/6] selftests/bpf: add icmp_send_unreach_recursion test Mahe Tardy
2025-07-25 18:53 ` [PATCH bpf-next v2 4/4] selftests/bpf: add icmp_send_unreach kfunc tests Mahe Tardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260420105816.72168-6-mahe.tardy@gmail.com \
--to=mahe.tardy@gmail.com \
--cc=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=coreteam@netfilter.org \
--cc=daniel@iogearbox.net \
--cc=fw@strlen.de \
--cc=john.fastabend@gmail.com \
--cc=lkp@intel.com \
--cc=martin.lau@linux.dev \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=oe-kbuild-all@lists.linux.dev \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox