Skip to content

Commit c642296

Browse files
ameryhungKernel Patches Daemon
authored andcommitted
selftests/bpf: Test tail call when cgroup storage is used
Make sure that if the owner of a program array map uses cgroup storage, (1) all callers must use cgroup storage and (2) the cgroup storage map used by all callers and callees must be the owner's cgroup storage map. Signed-off-by: Amery Hung <[email protected]>
1 parent 7bbc5ae commit c642296

File tree

4 files changed

+218
-0
lines changed

4 files changed

+218
-0
lines changed

tools/testing/selftests/bpf/prog_tests/tailcalls.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include "tailcall_freplace.skel.h"
99
#include "tc_bpf2bpf.skel.h"
1010
#include "tailcall_fail.skel.h"
11+
#include "tailcall_cgrp_storage_owner.skel.h"
12+
#include "tailcall_cgrp_storage_no_storage.skel.h"
13+
#include "tailcall_cgrp_storage.skel.h"
1114

1215
/* test_tailcall_1 checks basic functionality by patching multiple locations
1316
* in a single program for a single tail call slot with nop->jmp, jmp->nop
@@ -1648,6 +1651,116 @@ static void test_tailcall_bpf2bpf_freplace(void)
16481651
tc_bpf2bpf__destroy(tc_skel);
16491652
}
16501653

1654+
/*
1655+
* test_tail_call_cgrp_storage checks that if the owner program of a program
1656+
* array uses cgroup storage, other callers and callees must also use the
1657+
* exact same cgroup storage.
1658+
*/
1659+
static void test_tailcall_cgrp_storage(void)
1660+
{
1661+
int err, prog_fd, prog_array_fd, storage_map_fd, key = 0;
1662+
struct tailcall_cgrp_storage_owner *owner_skel;
1663+
struct tailcall_cgrp_storage *skel;
1664+
1665+
/* Load owner_skel first to make sure it becomes the owner of prog_array */
1666+
owner_skel = tailcall_cgrp_storage_owner__open_and_load();
1667+
if (!ASSERT_OK_PTR(owner_skel, "tailcall_cgrp_storage_owner__open_and_load"))
1668+
return;
1669+
1670+
prog_array_fd = bpf_map__fd(owner_skel->maps.prog_array);
1671+
storage_map_fd = bpf_map__fd(owner_skel->maps.storage_map);
1672+
1673+
skel = tailcall_cgrp_storage__open();
1674+
if (!ASSERT_OK_PTR(skel, "tailcall_cgrp_storage__open")) {
1675+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1676+
return;
1677+
}
1678+
1679+
err = bpf_map__reuse_fd(skel->maps.prog_array, prog_array_fd);
1680+
ASSERT_OK(err, "bpf_map__reuse_fd(prog_array)");
1681+
1682+
err = bpf_map__reuse_fd(skel->maps.storage_map, storage_map_fd);
1683+
ASSERT_OK(err, "bpf_map__reuse_fd(storage_map)");
1684+
1685+
err = bpf_object__load(skel->obj);
1686+
ASSERT_OK(err, "bpf_object__load");
1687+
1688+
prog_fd = bpf_program__fd(skel->progs.callee_prog);
1689+
1690+
err = bpf_map_update_elem(prog_array_fd, &key, &prog_fd, BPF_ANY);
1691+
ASSERT_OK(err, "bpf_map_update_elem(prog_array)");
1692+
1693+
tailcall_cgrp_storage__destroy(skel);
1694+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1695+
}
1696+
1697+
/*
1698+
* test_tail_call_cgrp_storage_diff_storage checks that a program using tail call
1699+
* is rejected if it uses a cgroup storage different from the owner's.
1700+
*/
1701+
static void test_tailcall_cgrp_storage_diff_storage(void)
1702+
{
1703+
struct tailcall_cgrp_storage_owner *owner_skel;
1704+
struct tailcall_cgrp_storage *skel;
1705+
int err, prog_array_fd;
1706+
1707+
/* Load owner_skel first to make sure it becomes the owner of prog_array */
1708+
owner_skel = tailcall_cgrp_storage_owner__open_and_load();
1709+
if (!ASSERT_OK_PTR(owner_skel, "tailcall_cgrp_storage_owner__open_and_load"))
1710+
return;
1711+
1712+
prog_array_fd = bpf_map__fd(owner_skel->maps.prog_array);
1713+
1714+
skel = tailcall_cgrp_storage__open();
1715+
if (!ASSERT_OK_PTR(skel, "tailcall_cgrp_storage__open")) {
1716+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1717+
return;
1718+
}
1719+
1720+
err = bpf_map__reuse_fd(skel->maps.prog_array, prog_array_fd);
1721+
ASSERT_OK(err, "bpf_map__reuse_fd(prog_array)");
1722+
1723+
err = bpf_object__load(skel->obj);
1724+
ASSERT_ERR(err, "bpf_object__load");
1725+
1726+
tailcall_cgrp_storage__destroy(skel);
1727+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1728+
}
1729+
1730+
/*
1731+
* test_tail_call_cgrp_storage_no_storage checks that a program using tail call
1732+
* is rejected if it does not use cgroup storage while the owner does.
1733+
*/
1734+
static void test_tailcall_cgrp_storage_no_storage(void)
1735+
{
1736+
struct tailcall_cgrp_storage_owner *owner_skel;
1737+
struct tailcall_cgrp_storage_no_storage *skel;
1738+
int err, prog_array_fd, storage_map_fd;
1739+
1740+
/* Load owner_skel first to make sure it becomes the owner of prog_array */
1741+
owner_skel = tailcall_cgrp_storage_owner__open_and_load();
1742+
if (!ASSERT_OK_PTR(owner_skel, "tailcall_cgrp_storage_owner__open_and_load"))
1743+
return;
1744+
1745+
prog_array_fd = bpf_map__fd(owner_skel->maps.prog_array);
1746+
storage_map_fd = bpf_map__fd(owner_skel->maps.storage_map);
1747+
1748+
skel = tailcall_cgrp_storage_no_storage__open();
1749+
if (!ASSERT_OK_PTR(skel, "tailcall_cgrp_storage_no_storage__open")) {
1750+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1751+
return;
1752+
}
1753+
1754+
err = bpf_map__reuse_fd(skel->maps.prog_array, prog_array_fd);
1755+
ASSERT_OK(err, "bpf_map__reuse_fd(prog_array)");
1756+
1757+
err = bpf_object__load(skel->obj);
1758+
ASSERT_ERR(err, "bpf_object__load");
1759+
1760+
tailcall_cgrp_storage_no_storage__destroy(skel);
1761+
tailcall_cgrp_storage_owner__destroy(owner_skel);
1762+
}
1763+
16511764
static void test_tailcall_failure()
16521765
{
16531766
RUN_TESTS(tailcall_fail);
@@ -1705,6 +1818,12 @@ void test_tailcalls(void)
17051818
test_tailcall_freplace();
17061819
if (test__start_subtest("tailcall_bpf2bpf_freplace"))
17071820
test_tailcall_bpf2bpf_freplace();
1821+
if (test__start_subtest("tailcall_cgrp_storage"))
1822+
test_tailcall_cgrp_storage();
1823+
if (test__start_subtest("tailcall_cgrp_storage_diff_storage"))
1824+
test_tailcall_cgrp_storage_diff_storage();
1825+
if (test__start_subtest("tailcall_cgrp_storage_no_storage"))
1826+
test_tailcall_cgrp_storage_no_storage();
17081827
if (test__start_subtest("tailcall_failure"))
17091828
test_tailcall_failure();
17101829
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
struct {
7+
__uint(type, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
8+
__type(key, struct bpf_cgroup_storage_key);
9+
__type(value, __u64);
10+
} storage_map SEC(".maps");
11+
12+
struct {
13+
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
14+
__uint(max_entries, 1);
15+
__uint(key_size, sizeof(__u32));
16+
__uint(value_size, sizeof(__u32));
17+
} prog_array SEC(".maps");
18+
19+
SEC("cgroup_skb/egress")
20+
int caller_prog(struct __sk_buff *skb)
21+
{
22+
__u64 *storage;
23+
24+
storage = bpf_get_local_storage(&storage_map, 0);
25+
if (storage)
26+
*storage = 1;
27+
28+
bpf_tail_call(skb, &prog_array, 0);
29+
30+
return 1;
31+
}
32+
33+
SEC("cgroup_skb/egress")
34+
int callee_prog(struct __sk_buff *skb)
35+
{
36+
__u64 *storage;
37+
38+
storage = bpf_get_local_storage(&storage_map, 0);
39+
if (storage)
40+
*storage = 1;
41+
42+
return 1;
43+
}
44+
45+
char _license[] SEC("license") = "GPL";
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
struct {
7+
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
8+
__uint(max_entries, 1);
9+
__uint(key_size, sizeof(__u32));
10+
__uint(value_size, sizeof(__u32));
11+
} prog_array SEC(".maps");
12+
13+
SEC("cgroup_skb/egress")
14+
int caller_prog(struct __sk_buff *skb)
15+
{
16+
bpf_tail_call(skb, &prog_array, 0);
17+
18+
return 1;
19+
}
20+
21+
char _license[] SEC("license") = "GPL";
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
struct {
7+
__uint(type, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
8+
__type(key, struct bpf_cgroup_storage_key);
9+
__type(value, __u64);
10+
} storage_map SEC(".maps");
11+
12+
struct {
13+
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
14+
__uint(max_entries, 1);
15+
__uint(key_size, sizeof(__u32));
16+
__uint(value_size, sizeof(__u32));
17+
} prog_array SEC(".maps");
18+
19+
SEC("cgroup_skb/egress")
20+
int prog_array_owner(struct __sk_buff *skb)
21+
{
22+
__u64 *storage;
23+
24+
storage = bpf_get_local_storage(&storage_map, 0);
25+
if (storage)
26+
*storage = 1;
27+
28+
bpf_tail_call(skb, &prog_array, 0);
29+
30+
return 1;
31+
}
32+
33+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)