Skip to content

Commit 50b3ed5

Browse files
Petar PenkovAlexei Starovoitov
authored andcommitted
selftests/bpf: test bpf flow dissection
Adds a test that sends different types of packets over multiple tunnels and verifies that valid packets are dissected correctly. To do so, a tc-flower rule is added to drop packets on UDP src port 9, and packets are sent from ports 8, 9, and 10. Only the packets on port 9 should be dropped. Because tc-flower relies on the flow dissector to match flows, correct classification demonstrates correct dissection. Also add support logic to load the BPF program and to inject the test packets. Signed-off-by: Petar Penkov <ppenkov@google.com> Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 9c98b13 commit 50b3ed5

File tree

8 files changed

+1134
-2
lines changed

8 files changed

+1134
-2
lines changed

tools/testing/selftests/bpf/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ test_skb_cgroup_id_user
2323
test_socket_cookie
2424
test_cgroup_storage
2525
test_select_reuseport
26+
test_flow_dissector
27+
flow_dissector_load

tools/testing/selftests/bpf/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ TEST_PROGS := test_kmod.sh \
4747
test_tunnel.sh \
4848
test_lwt_seg6local.sh \
4949
test_lirc_mode2.sh \
50-
test_skb_cgroup_id.sh
50+
test_skb_cgroup_id.sh \
51+
test_flow_dissector.sh
5152

5253
# Compile but not part of 'make run_tests'
53-
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user
54+
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \
55+
flow_dissector_load test_flow_dissector
5456

5557
include ../lib.mk
5658

tools/testing/selftests/bpf/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ CONFIG_CRYPTO_HMAC=m
1818
CONFIG_CRYPTO_SHA256=m
1919
CONFIG_VXLAN=y
2020
CONFIG_GENEVE=y
21+
CONFIG_NET_CLS_FLOWER=m
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <error.h>
3+
#include <errno.h>
4+
#include <getopt.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <sys/stat.h>
9+
#include <fcntl.h>
10+
#include <unistd.h>
11+
#include <bpf/bpf.h>
12+
#include <bpf/libbpf.h>
13+
14+
const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector";
15+
const char *cfg_map_name = "jmp_table";
16+
bool cfg_attach = true;
17+
char *cfg_section_name;
18+
char *cfg_path_name;
19+
20+
static void load_and_attach_program(void)
21+
{
22+
struct bpf_program *prog, *main_prog;
23+
struct bpf_map *prog_array;
24+
int i, fd, prog_fd, ret;
25+
struct bpf_object *obj;
26+
int prog_array_fd;
27+
28+
ret = bpf_prog_load(cfg_path_name, BPF_PROG_TYPE_FLOW_DISSECTOR, &obj,
29+
&prog_fd);
30+
if (ret)
31+
error(1, 0, "bpf_prog_load %s", cfg_path_name);
32+
33+
main_prog = bpf_object__find_program_by_title(obj, cfg_section_name);
34+
if (!main_prog)
35+
error(1, 0, "bpf_object__find_program_by_title %s",
36+
cfg_section_name);
37+
38+
prog_fd = bpf_program__fd(main_prog);
39+
if (prog_fd < 0)
40+
error(1, 0, "bpf_program__fd");
41+
42+
prog_array = bpf_object__find_map_by_name(obj, cfg_map_name);
43+
if (!prog_array)
44+
error(1, 0, "bpf_object__find_map_by_name %s", cfg_map_name);
45+
46+
prog_array_fd = bpf_map__fd(prog_array);
47+
if (prog_array_fd < 0)
48+
error(1, 0, "bpf_map__fd %s", cfg_map_name);
49+
50+
i = 0;
51+
bpf_object__for_each_program(prog, obj) {
52+
fd = bpf_program__fd(prog);
53+
if (fd < 0)
54+
error(1, 0, "bpf_program__fd");
55+
56+
if (fd != prog_fd) {
57+
printf("%d: %s\n", i, bpf_program__title(prog, false));
58+
bpf_map_update_elem(prog_array_fd, &i, &fd, BPF_ANY);
59+
++i;
60+
}
61+
}
62+
63+
ret = bpf_prog_attach(prog_fd, 0 /* Ignore */, BPF_FLOW_DISSECTOR, 0);
64+
if (ret)
65+
error(1, 0, "bpf_prog_attach %s", cfg_path_name);
66+
67+
ret = bpf_object__pin(obj, cfg_pin_path);
68+
if (ret)
69+
error(1, 0, "bpf_object__pin %s", cfg_pin_path);
70+
71+
}
72+
73+
static void detach_program(void)
74+
{
75+
char command[64];
76+
int ret;
77+
78+
ret = bpf_prog_detach(0, BPF_FLOW_DISSECTOR);
79+
if (ret)
80+
error(1, 0, "bpf_prog_detach");
81+
82+
/* To unpin, it is necessary and sufficient to just remove this dir */
83+
sprintf(command, "rm -r %s", cfg_pin_path);
84+
ret = system(command);
85+
if (ret)
86+
error(1, errno, command);
87+
}
88+
89+
static void parse_opts(int argc, char **argv)
90+
{
91+
bool attach = false;
92+
bool detach = false;
93+
int c;
94+
95+
while ((c = getopt(argc, argv, "adp:s:")) != -1) {
96+
switch (c) {
97+
case 'a':
98+
if (detach)
99+
error(1, 0, "attach/detach are exclusive");
100+
attach = true;
101+
break;
102+
case 'd':
103+
if (attach)
104+
error(1, 0, "attach/detach are exclusive");
105+
detach = true;
106+
break;
107+
case 'p':
108+
if (cfg_path_name)
109+
error(1, 0, "only one prog name can be given");
110+
111+
cfg_path_name = optarg;
112+
break;
113+
case 's':
114+
if (cfg_section_name)
115+
error(1, 0, "only one section can be given");
116+
117+
cfg_section_name = optarg;
118+
break;
119+
}
120+
}
121+
122+
if (detach)
123+
cfg_attach = false;
124+
125+
if (cfg_attach && !cfg_path_name)
126+
error(1, 0, "must provide a path to the BPF program");
127+
128+
if (cfg_attach && !cfg_section_name)
129+
error(1, 0, "must provide a section name");
130+
}
131+
132+
int main(int argc, char **argv)
133+
{
134+
parse_opts(argc, argv);
135+
if (cfg_attach)
136+
load_and_attach_program();
137+
else
138+
detach_program();
139+
return 0;
140+
}

0 commit comments

Comments
 (0)