Skip to content

Commit f957c23

Browse files
TropicaoMartin KaFai Lau
authored and
Martin KaFai Lau
committed
selftests/bpf: convert test_skb_cgroup_id_user to test_progs
test_skb_cgroup_id_user allows testing skb cgroup id retrieval at different levels, but is not integrated in test_progs, so it is not run automatically in CI. The test overlaps a bit with cgroup_skb_sk_lookup_kern, which is integrated in test_progs and test extensively skb cgroup helpers, but there is still one major difference between the two tests which justifies the conversion: cgroup_skb_sk_lookup_kern deals with a BPF_PROG_TYPE_CGROUP_SKB (attached on a cgroup), while test_skb_cgroup_id_user deals with a BPF_PROG_TYPE_SCHED_CLS (attached on a qdisc) Convert test_skb_cgroup_id_user into test_progs framework in order to run it automatically in CI. The main differences with the original test are the following: - rename the test to make it shorter and more straightforward regarding tested feature - the wrapping shell script has been dropped since every setup step is now handled in the main C test file - the test has been renamed for a shorter name and reflecting the tested API - add dedicated assert log per level to ease test failure debugging - use global variables instead of maps to access bpf prog data Signed-off-by: Alexis Lothoré (eBPF Foundation) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin KaFai Lau <[email protected]>
1 parent 7b4400a commit f957c23

File tree

6 files changed

+160
-276
lines changed

6 files changed

+160
-276
lines changed

tools/testing/selftests/bpf/.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ test_sock
1919
urandom_read
2020
test_sockmap
2121
test_lirc_mode2_user
22-
test_skb_cgroup_id_user
2322
test_flow_dissector
2423
flow_dissector_load
2524
test_tcpnotify_user

tools/testing/selftests/bpf/Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
137137
test_xdp_vlan.sh test_bpftool.py
138138

139139
# Compile but not part of 'make run_tests'
140-
TEST_GEN_PROGS_EXTENDED = test_skb_cgroup_id_user \
140+
TEST_GEN_PROGS_EXTENDED = \
141141
flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
142142
test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
143143
xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \
@@ -290,7 +290,6 @@ JSON_WRITER := $(OUTPUT)/json_writer.o
290290
CAP_HELPERS := $(OUTPUT)/cap_helpers.o
291291
NETWORK_HELPERS := $(OUTPUT)/network_helpers.o
292292

293-
$(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
294293
$(OUTPUT)/test_sock: $(CGROUP_HELPERS) $(TESTING_HELPERS)
295294
$(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS)
296295
$(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "test_progs.h"
4+
#include "network_helpers.h"
5+
#include "cgroup_helpers.h"
6+
#include "cgroup_ancestor.skel.h"
7+
8+
#define CGROUP_PATH "/skb_cgroup_test"
9+
#define TEST_NS "cgroup_ancestor_ns"
10+
#define NUM_CGROUP_LEVELS 4
11+
#define WAIT_AUTO_IP_MAX_ATTEMPT 10
12+
#define DST_ADDR "::1"
13+
#define DST_PORT 1234
14+
#define MAX_ASSERT_NAME 32
15+
16+
struct test_data {
17+
struct cgroup_ancestor *skel;
18+
struct bpf_tc_hook qdisc;
19+
struct bpf_tc_opts tc_attach;
20+
struct nstoken *ns;
21+
};
22+
23+
static int send_datagram(void)
24+
{
25+
unsigned char buf[] = "some random test data";
26+
struct sockaddr_in6 addr = { .sin6_family = AF_INET6,
27+
.sin6_port = htons(DST_PORT), };
28+
int sock, n;
29+
30+
if (!ASSERT_EQ(inet_pton(AF_INET6, DST_ADDR, &addr.sin6_addr), 1,
31+
"inet_pton"))
32+
return -1;
33+
34+
sock = socket(AF_INET6, SOCK_DGRAM, 0);
35+
if (!ASSERT_OK_FD(sock, "create socket"))
36+
return sock;
37+
38+
if (!ASSERT_OK(connect(sock, &addr, sizeof(addr)), "connect")) {
39+
close(sock);
40+
return -1;
41+
}
42+
43+
n = sendto(sock, buf, sizeof(buf), 0, (const struct sockaddr *)&addr,
44+
sizeof(addr));
45+
close(sock);
46+
return ASSERT_EQ(n, sizeof(buf), "send data") ? 0 : -1;
47+
}
48+
49+
static int setup_network(struct test_data *t)
50+
{
51+
SYS(fail, "ip netns add %s", TEST_NS);
52+
t->ns = open_netns(TEST_NS);
53+
if (!ASSERT_OK_PTR(t->ns, "open netns"))
54+
goto cleanup_ns;
55+
56+
SYS(close_ns, "ip link set lo up");
57+
58+
memset(&t->qdisc, 0, sizeof(t->qdisc));
59+
t->qdisc.sz = sizeof(t->qdisc);
60+
t->qdisc.attach_point = BPF_TC_EGRESS;
61+
t->qdisc.ifindex = if_nametoindex("lo");
62+
if (!ASSERT_NEQ(t->qdisc.ifindex, 0, "if_nametoindex"))
63+
goto close_ns;
64+
if (!ASSERT_OK(bpf_tc_hook_create(&t->qdisc), "qdisc add"))
65+
goto close_ns;
66+
67+
memset(&t->tc_attach, 0, sizeof(t->tc_attach));
68+
t->tc_attach.sz = sizeof(t->tc_attach);
69+
t->tc_attach.prog_fd = bpf_program__fd(t->skel->progs.log_cgroup_id);
70+
if (!ASSERT_OK(bpf_tc_attach(&t->qdisc, &t->tc_attach), "filter add"))
71+
goto cleanup_qdisc;
72+
73+
return 0;
74+
75+
cleanup_qdisc:
76+
bpf_tc_hook_destroy(&t->qdisc);
77+
close_ns:
78+
close_netns(t->ns);
79+
cleanup_ns:
80+
SYS_NOFAIL("ip netns del %s", TEST_NS);
81+
fail:
82+
return 1;
83+
}
84+
85+
static void cleanup_network(struct test_data *t)
86+
{
87+
bpf_tc_detach(&t->qdisc, &t->tc_attach);
88+
bpf_tc_hook_destroy(&t->qdisc);
89+
close_netns(t->ns);
90+
SYS_NOFAIL("ip netns del %s", TEST_NS);
91+
}
92+
93+
static void check_ancestors_ids(struct test_data *t)
94+
{
95+
__u64 expected_ids[NUM_CGROUP_LEVELS];
96+
char assert_name[MAX_ASSERT_NAME];
97+
__u32 level;
98+
99+
expected_ids[0] = get_cgroup_id("/.."); /* root cgroup */
100+
expected_ids[1] = get_cgroup_id("");
101+
expected_ids[2] = get_cgroup_id(CGROUP_PATH);
102+
expected_ids[3] = 0; /* non-existent cgroup */
103+
104+
for (level = 0; level < NUM_CGROUP_LEVELS; level++) {
105+
snprintf(assert_name, MAX_ASSERT_NAME,
106+
"ancestor id at level %d", level);
107+
ASSERT_EQ(t->skel->bss->cgroup_ids[level], expected_ids[level],
108+
assert_name);
109+
}
110+
}
111+
112+
void test_cgroup_ancestor(void)
113+
{
114+
struct test_data t;
115+
int cgroup_fd;
116+
117+
t.skel = cgroup_ancestor__open_and_load();
118+
if (!ASSERT_OK_PTR(t.skel, "open and load"))
119+
return;
120+
121+
t.skel->bss->dport = htons(DST_PORT);
122+
cgroup_fd = cgroup_setup_and_join(CGROUP_PATH);
123+
if (cgroup_fd < 0)
124+
goto cleanup_progs;
125+
126+
if (setup_network(&t))
127+
goto cleanup_cgroups;
128+
129+
if (send_datagram())
130+
goto cleanup_network;
131+
132+
check_ancestors_ids(&t);
133+
134+
cleanup_network:
135+
cleanup_network(&t);
136+
cleanup_cgroups:
137+
close(cgroup_fd);
138+
cleanup_cgroup_environment();
139+
cleanup_progs:
140+
cgroup_ancestor__destroy(t.skel);
141+
}

tools/testing/selftests/bpf/progs/cgroup_ancestor.c

+18-23
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
11
// SPDX-License-Identifier: GPL-2.0
22
// Copyright (c) 2018 Facebook
33

4-
#include <linux/bpf.h>
5-
#include <linux/pkt_cls.h>
6-
7-
#include <string.h>
8-
4+
#include <vmlinux.h>
95
#include <bpf/bpf_helpers.h>
10-
6+
#include <bpf/bpf_core_read.h>
7+
#include "bpf_tracing_net.h"
118
#define NUM_CGROUP_LEVELS 4
129

13-
struct {
14-
__uint(type, BPF_MAP_TYPE_ARRAY);
15-
__type(key, __u32);
16-
__type(value, __u64);
17-
__uint(max_entries, NUM_CGROUP_LEVELS);
18-
} cgroup_ids SEC(".maps");
10+
__u64 cgroup_ids[NUM_CGROUP_LEVELS];
11+
__u16 dport;
1912

2013
static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level)
2114
{
22-
__u64 id;
23-
2415
/* [1] &level passed to external function that may change it, it's
2516
* incompatible with loop unroll.
2617
*/
27-
id = bpf_skb_ancestor_cgroup_id(skb, level);
28-
bpf_map_update_elem(&cgroup_ids, &level, &id, 0);
18+
cgroup_ids[level] = bpf_skb_ancestor_cgroup_id(skb, level);
2919
}
3020

3121
SEC("tc")
3222
int log_cgroup_id(struct __sk_buff *skb)
3323
{
34-
/* Loop unroll can't be used here due to [1]. Unrolling manually.
35-
* Number of calls should be in sync with NUM_CGROUP_LEVELS.
36-
*/
37-
log_nth_level(skb, 0);
38-
log_nth_level(skb, 1);
39-
log_nth_level(skb, 2);
40-
log_nth_level(skb, 3);
24+
struct sock *sk = (void *)skb->sk;
25+
26+
if (!sk)
27+
return TC_ACT_OK;
28+
29+
sk = bpf_core_cast(sk, struct sock);
30+
if (sk->sk_protocol == IPPROTO_UDP && sk->sk_dport == dport) {
31+
log_nth_level(skb, 0);
32+
log_nth_level(skb, 1);
33+
log_nth_level(skb, 2);
34+
log_nth_level(skb, 3);
35+
}
4136

4237
return TC_ACT_OK;
4338
}

tools/testing/selftests/bpf/test_skb_cgroup_id.sh

-67
This file was deleted.

0 commit comments

Comments
 (0)