From: Weiming Shi <bestswngs@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>, Shuah Khan <shuah@kernel.org>
Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, linux-kselftest@vger.kernel.org,
Xiang Mei <xmei5@asu.edu>, Weiming Shi <bestswngs@gmail.com>
Subject: [PATCH v4 2/2] selftests/bpf: cover stale CB after LWT IP encapsulation
Date: Tue, 22 Sep 2026 01:39:10 +0800 [thread overview]
Message-ID: <20260921173910.90847-3-bestswngs@gmail.com> (raw)
In-Reply-To: <20260921173910.90847-1-bestswngs@gmail.com>
Add compact regression coverage to the existing LWT IP encapsulation
test. Send an IPv4 ping with a Record Route option through an ingress LWT
program which prepends a TTL-one IPv4 header, then observe __icmp_send()
with fentry and verify that the restored protocol control block no longer
contains the inner header's cached option offsets.
Read ctx->cb[0] in the LWT program so the test exercises
bpf_prog_run_save_cb()'s save/restore path before the post-run check.
Link: https://lore.kernel.org/bpf/DLKB3UXOH0IS.1UL8NV9HSJFXG@gmail.com/
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
.../selftests/bpf/prog_tests/lwt_ip_encap.c | 45 ++++++++++++++++++
.../selftests/bpf/progs/test_lwt_ip_encap.c | 47 +++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c b/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c
index 39e8a3b8b6af..14ba33eaeb96 100644
--- a/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c
+++ b/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c
@@ -686,3 +686,48 @@ void test_lwt_ip_encap_vxlan_ipv6(void)
{
lwt_ip_encap_vxlan(IPV6_ENCAP);
}
+
+void test_lwt_ip_encap_stale_cb(void)
+{
+ char ns1[NETNS_NAME_SIZE] = NETNS_BASE "-1-";
+ char ns2[NETNS_NAME_SIZE] = NETNS_BASE "-2-";
+ char ns3[NETNS_NAME_SIZE] = NETNS_BASE "-3-";
+ struct test_lwt_ip_encap *skel = NULL;
+
+ if (!ASSERT_OK(create_ns(ns1, NETNS_NAME_SIZE), "create ns1"))
+ goto out;
+ if (!ASSERT_OK(create_ns(ns2, NETNS_NAME_SIZE), "create ns2"))
+ goto out;
+ if (!ASSERT_OK(create_ns(ns3, NETNS_NAME_SIZE), "create ns3"))
+ goto out;
+ if (!ASSERT_OK(setup_network(ns1, ns2, ns3, ""), "setup network"))
+ goto out;
+
+ skel = test_lwt_ip_encap__open();
+ if (!ASSERT_OK_PTR(skel, "open"))
+ goto out;
+ bpf_program__set_autoload(skel->progs.bpf_lwt_encap_gre, false);
+ bpf_program__set_autoload(skel->progs.bpf_lwt_encap_gre6, false);
+ bpf_program__set_autoload(skel->progs.bpf_lwt_encap_vxlan, false);
+ bpf_program__set_autoload(skel->progs.bpf_lwt_encap_vxlan6, false);
+ bpf_program__set_autoload(skel->progs.bpf_lwt_encap_stale, false);
+ if (!ASSERT_OK(test_lwt_ip_encap__load(skel), "load"))
+ goto out;
+ if (!ASSERT_OK(test_lwt_ip_encap__attach(skel), "attach"))
+ goto out;
+
+ SYS(out, "ip -n %s route replace %s/32 encap bpf in obj %s sec encap_stale dev veth3",
+ ns2, IP4_ADDR_DST, BPF_FILE);
+ skel->bss->stale_cb_seen = false;
+ skel->bss->stale_cb_cleared = false;
+ SYS_NOFAIL("ip netns exec %s ping -q -R -c 1 -W 1 -I veth1 %s >/dev/null 2>&1",
+ ns1, IP4_ADDR_DST);
+ ASSERT_TRUE(skel->bss->stale_cb_seen, "stale_cb_seen");
+ ASSERT_TRUE(skel->bss->stale_cb_cleared, "stale_cb_cleared");
+
+out:
+ test_lwt_ip_encap__destroy(skel);
+ SYS_NOFAIL("ip netns del %s", ns1);
+ SYS_NOFAIL("ip netns del %s", ns2);
+ SYS_NOFAIL("ip netns del %s", ns3);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c b/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c
index 4a934fccf8f5..8b57c7fb7fa8 100644
--- a/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c
+++ b/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <string.h>
+#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_tracing.h>
@@ -10,6 +11,8 @@ struct grehdr {
__be16 protocol;
};
+#define ICMP_TIME_EXCEEDED 11
+
SEC("encap_gre")
int bpf_lwt_encap_gre(struct __sk_buff *skb)
{
@@ -80,6 +83,29 @@ int bpf_lwt_encap_gre6(struct __sk_buff *skb)
return BPF_LWT_REROUTE;
}
+SEC("encap_stale")
+int bpf_lwt_encap_stale(struct __sk_buff *skb)
+{
+ struct iphdr iph = {};
+
+ /* Exercise CB restore before post-run invalidation. */
+ if (skb->cb[0])
+ return BPF_DROP;
+
+ iph.version = 4;
+ iph.ihl = 5;
+ iph.ttl = 1;
+ iph.protocol = IPPROTO_IPIP;
+ iph.tot_len = bpf_htons(skb->len + sizeof(iph));
+ iph.saddr = bpf_htonl(0xac100264); /* 172.16.2.100 */
+ iph.daddr = bpf_htonl(0xac100464); /* 172.16.4.100 */
+
+ if (bpf_lwt_push_encap(skb, BPF_LWT_ENCAP_IP, &iph, sizeof(iph)))
+ return BPF_DROP;
+
+ return BPF_OK;
+}
+
#define VXLAN_PORT 4789
#define VXLAN_FLAGS 0x08000000
#define VXLAN_VNI 1
@@ -194,6 +220,27 @@ volatile const int tgt_ip_version;
__u16 transport_hdr = 0;
__u16 network_hdr = 0;
bool fexit_triggered = false;
+bool stale_cb_cleared = false;
+bool stale_cb_seen = false;
+
+SEC("fentry/__icmp_send")
+int BPF_PROG(fentry_icmp_send, struct sk_buff *skb, int type, int code,
+ __be32 info, const struct inet_skb_parm *parm)
+{
+ struct iphdr *iph;
+
+ if (type != ICMP_TIME_EXCEEDED)
+ return 0;
+
+ iph = (void *)BPF_CORE_READ(skb, head) + BPF_CORE_READ(skb, network_header);
+ if (BPF_CORE_READ(iph, daddr) != bpf_htonl(0xac100464))
+ return 0;
+
+ stale_cb_seen = true;
+ stale_cb_cleared = !BPF_CORE_READ(parm, opt.optlen) &&
+ !BPF_CORE_READ(parm, opt.rr);
+ return 0;
+}
SEC("?fexit/bpf_lwt_push_ip_encap")
int BPF_PROG(fexit_lwt_push_ip_encap, struct sk_buff *skb, void *hdr, u32 len, bool ingress,
--
2.55.0
next prev parent reply other threads:[~2026-09-21 17:40 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 17:39 [PATCH v4 0/2] bpf: clear stale IPv4 options after LWT encapsulation Weiming Shi
2026-09-21 17:39 ` [PATCH v4 1/2] " Weiming Shi
2026-09-21 17:39 ` Weiming Shi [this message]
2026-09-21 17:56 ` [PATCH v4 2/2] selftests/bpf: cover stale CB after LWT IP encapsulation sashiko-bot
2026-09-21 18:38 ` bot+bpf-ci
2026-09-22 13:37 ` Daniel Borkmann
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=20260921173910.90847-3-bestswngs@gmail.com \
--to=bestswngs@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=emil@etsalapatis.com \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=xmei5@asu.edu \
--cc=yonghong.song@linux.dev \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.