selftests/bpf: Add tests for bpf_redirect_peer with BPF_F_EGRESS

Extend redirect tests to cover bpf_redirect_peer(BPF_F_EGRESS). SRC
redirects to DST using bpf_redirect_peer(BPF_F_EGRESS) then traffic is
hairpinned into DST using bpf_redirect.

Signed-off-by: Jordan Rife <jordan@jrife.io>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Paul Chaignon <paul.chaignon@gmail.com>
Link: https://lore.kernel.org/r/20260618182035.43811-3-jordan@jrife.io
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Jordan Rife
2026-06-18 11:20:33 -07:00
committed by Alexei Starovoitov
parent 509ca545d4
commit 006b9456e9
2 changed files with 90 additions and 0 deletions

View File

@@ -192,6 +192,8 @@ static int create_netkit(int mode, char *prim, char *peer)
req.n.nlmsg_len += sizeof(struct ifinfomsg);
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, peer, strlen(peer));
addattr_nest_end(&req.n, peer_info);
addattr32(&req.n, sizeof(req), IFLA_NETKIT_SCRUB,
NETKIT_SCRUB_NONE);
addattr_nest_end(&req.n, data);
addattr_nest_end(&req.n, linkinfo);
@@ -405,6 +407,24 @@ static int netns_load_bpf(const struct bpf_program *src_prog,
return -1;
}
static struct bpf_link *netns_attach_nk(const char *ns, int ifindex,
struct bpf_program *prog)
{
LIBBPF_OPTS(bpf_netkit_opts, optl);
struct nstoken *nstoken = NULL;
struct bpf_link *link = NULL;
nstoken = open_netns(ns);
if (!ASSERT_OK_PTR(nstoken, "setns"))
goto cleanup;
link = bpf_program__attach_netkit(prog, ifindex, &optl);
cleanup:
if (nstoken)
close_netns(nstoken);
return link;
}
static void test_tcp(int family, const char *addr, __u16 port)
{
int listen_fd = -1, accept_fd = -1, client_fd = -1;
@@ -1082,6 +1102,53 @@ static void test_tc_redirect_peer(struct netns_setup_result *setup_result)
close_netns(nstoken);
}
static void test_tc_redirect_peer_ing(struct netns_setup_result *setup_result)
{
struct test_tc_peer *skel;
struct nstoken *nstoken;
int err;
nstoken = open_netns(NS_FWD);
if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
return;
skel = test_tc_peer__open();
if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
goto done;
skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd;
skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc_src_ing,
BPF_NETKIT_PRIMARY), 0, "src_prog_attach_type");
ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc_dst_ing,
BPF_NETKIT_PRIMARY), 0, "dst_prog_attach_type");
err = test_tc_peer__load(skel);
if (!ASSERT_OK(err, "test_tc_peer__load"))
goto done;
skel->links.tc_src_ing = netns_attach_nk(NS_SRC,
setup_result->ifindex_src,
skel->progs.tc_src_ing);
if (!ASSERT_OK_PTR(skel->links.tc_src_ing, "attach_src"))
goto done;
skel->links.tc_dst_ing = netns_attach_nk(NS_DST,
setup_result->ifindex_dst,
skel->progs.tc_dst_ing);
if (!ASSERT_OK_PTR(skel->links.tc_dst_ing, "attach_dst"))
goto done;
if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
goto done;
test_connectivity();
done:
if (skel)
test_tc_peer__destroy(skel);
close_netns(nstoken);
}
static int tun_open(char *name)
{
struct ifreq ifr;
@@ -1280,6 +1347,7 @@ static void *test_tc_redirect_run_tests(void *arg)
RUN_TEST(tc_redirect_peer, MODE_VETH);
RUN_TEST(tc_redirect_peer, MODE_NETKIT);
RUN_TEST(tc_redirect_peer_ing, MODE_NETKIT);
RUN_TEST(tc_redirect_peer_l3, MODE_VETH);
RUN_TEST(tc_redirect_peer_l3, MODE_NETKIT);
RUN_TEST(tc_redirect_neigh, MODE_VETH);

View File

@@ -34,6 +34,28 @@ int tc_src(struct __sk_buff *skb)
return bpf_redirect_peer(IFINDEX_DST, 0);
}
SEC("tc")
int tc_dst_ing(struct __sk_buff *skb)
{
if (!skb->mark) {
skb->mark = 0x1;
return bpf_redirect_peer(IFINDEX_SRC, BPF_F_EGRESS);
}
return bpf_redirect(IFINDEX_DST, 0);
}
SEC("tc")
int tc_src_ing(struct __sk_buff *skb)
{
if (!skb->mark) {
skb->mark = 0x1;
return bpf_redirect_peer(IFINDEX_DST, BPF_F_EGRESS);
}
return bpf_redirect(IFINDEX_SRC, 0);
}
SEC("tc")
int tc_dst_l3(struct __sk_buff *skb)
{