Daniel Borkmann says:
====================
bpf-next 2021-10-02
We've added 85 non-merge commits during the last 15 day(s) which contain
a total of 132 files changed, 13779 insertions(+), 6724 deletions(-).
The main changes are:
1) Massive update on test_bpf.ko coverage for JITs as preparatory work for
an upcoming MIPS eBPF JIT, from Johan Almbladh.
2) Add a batched interface for RX buffer allocation in AF_XDP buffer pool,
with driver support for i40e and ice from Magnus Karlsson.
3) Add legacy uprobe support to libbpf to complement recently merged legacy
kprobe support, from Andrii Nakryiko.
4) Add bpf_trace_vprintk() as variadic printk helper, from Dave Marchevsky.
5) Support saving the register state in verifier when spilling <8byte bounded
scalar to the stack, from Martin Lau.
6) Add libbpf opt-in for stricter BPF program section name handling as part
of libbpf 1.0 effort, from Andrii Nakryiko.
7) Add a document to help clarifying BPF licensing, from Alexei Starovoitov.
8) Fix skel_internal.h to propagate errno if the loader indicates an internal
error, from Kumar Kartikeya Dwivedi.
9) Fix build warnings with -Wcast-function-type so that the option can later
be enabled by default for the kernel, from Kees Cook.
10) Fix libbpf to ignore STT_SECTION symbols in legacy map definitions as it
otherwise errors out when encountering them, from Toke Høiland-Jørgensen.
11) Teach libbpf to recognize specialized maps (such as for perf RB) and
internally remove BTF type IDs when creating them, from Hengqi Chen.
12) Various fixes and improvements to BPF selftests.
====================
Link: https://lore.kernel.org/r/20211002001327.15169-1-daniel@iogearbox.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -315,7 +315,8 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
|
||||
linked_vars.skel.h linked_maps.skel.h
|
||||
|
||||
LSKELS := kfunc_call_test.c fentry_test.c fexit_test.c fexit_sleep.c \
|
||||
test_ksyms_module.c test_ringbuf.c atomics.c trace_printk.c
|
||||
test_ksyms_module.c test_ringbuf.c atomics.c trace_printk.c \
|
||||
trace_vprintk.c
|
||||
SKEL_BLACKLIST += $$(LSKELS)
|
||||
|
||||
test_static_linked.skel.h-deps := test_static_linked1.o test_static_linked2.o
|
||||
|
||||
@@ -242,3 +242,16 @@ To fix this issue, user newer libbpf.
|
||||
.. Links
|
||||
.. _clang reloc patch: https://reviews.llvm.org/D102712
|
||||
.. _kernel llvm reloc: /Documentation/bpf/llvm_reloc.rst
|
||||
|
||||
Clang dependencies for the u32 spill test (xdpwall)
|
||||
===================================================
|
||||
The xdpwall selftest requires a change in `Clang 14`__.
|
||||
|
||||
Without it, the xdpwall selftest will fail and the error message
|
||||
from running test_progs will look like:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
test_xdpwall:FAIL:Does LLVM have https://reviews.llvm.org/D109073? unexpected error: -4007
|
||||
|
||||
__ https://reviews.llvm.org/D109073
|
||||
|
||||
@@ -14,6 +14,20 @@ void test_attach_probe(void)
|
||||
struct test_attach_probe* skel;
|
||||
size_t uprobe_offset;
|
||||
ssize_t base_addr, ref_ctr_offset;
|
||||
bool legacy;
|
||||
|
||||
/* Check if new-style kprobe/uprobe API is supported.
|
||||
* Kernels that support new FD-based kprobe and uprobe BPF attachment
|
||||
* through perf_event_open() syscall expose
|
||||
* /sys/bus/event_source/devices/kprobe/type and
|
||||
* /sys/bus/event_source/devices/uprobe/type files, respectively. They
|
||||
* contain magic numbers that are passed as "type" field of
|
||||
* perf_event_attr. Lack of such file in the system indicates legacy
|
||||
* kernel with old-style kprobe/uprobe attach interface through
|
||||
* creating per-probe event through tracefs. For such cases
|
||||
* ref_ctr_offset feature is not supported, so we don't test it.
|
||||
*/
|
||||
legacy = access("/sys/bus/event_source/devices/kprobe/type", F_OK) != 0;
|
||||
|
||||
base_addr = get_base_addr();
|
||||
if (CHECK(base_addr < 0, "get_base_addr",
|
||||
@@ -45,10 +59,11 @@ void test_attach_probe(void)
|
||||
goto cleanup;
|
||||
skel->links.handle_kretprobe = kretprobe_link;
|
||||
|
||||
ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before");
|
||||
if (!legacy)
|
||||
ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before");
|
||||
|
||||
uprobe_opts.retprobe = false;
|
||||
uprobe_opts.ref_ctr_offset = ref_ctr_offset;
|
||||
uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset;
|
||||
uprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe,
|
||||
0 /* self pid */,
|
||||
"/proc/self/exe",
|
||||
@@ -58,11 +73,12 @@ void test_attach_probe(void)
|
||||
goto cleanup;
|
||||
skel->links.handle_uprobe = uprobe_link;
|
||||
|
||||
ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after");
|
||||
if (!legacy)
|
||||
ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after");
|
||||
|
||||
/* if uprobe uses ref_ctr, uretprobe has to use ref_ctr as well */
|
||||
uprobe_opts.retprobe = true;
|
||||
uprobe_opts.ref_ctr_offset = ref_ctr_offset;
|
||||
uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset;
|
||||
uretprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe,
|
||||
-1 /* any pid */,
|
||||
"/proc/self/exe",
|
||||
|
||||
@@ -358,12 +358,27 @@ static void test_btf_dump_int_data(struct btf *btf, struct btf_dump *d,
|
||||
TEST_BTF_DUMP_DATA_OVER(btf, d, NULL, str, int, sizeof(int)-1, "", 1);
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128, BTF_F_COMPACT,
|
||||
"(__int128)0xffffffffffffffff",
|
||||
0xffffffffffffffff);
|
||||
ASSERT_OK(btf_dump_data(btf, d, "__int128", NULL, 0, &i, 16, str,
|
||||
"(__int128)0xfffffffffffffffffffffffffffffffe"),
|
||||
"dump __int128");
|
||||
/* gcc encode unsigned __int128 type with name "__int128 unsigned" in dwarf,
|
||||
* and clang encode it with name "unsigned __int128" in dwarf.
|
||||
* Do an availability test for either variant before doing actual test.
|
||||
*/
|
||||
if (btf__find_by_name(btf, "unsigned __int128") > 0) {
|
||||
TEST_BTF_DUMP_DATA(btf, d, NULL, str, unsigned __int128, BTF_F_COMPACT,
|
||||
"(unsigned __int128)0xffffffffffffffff",
|
||||
0xffffffffffffffff);
|
||||
ASSERT_OK(btf_dump_data(btf, d, "unsigned __int128", NULL, 0, &i, 16, str,
|
||||
"(unsigned __int128)0xfffffffffffffffffffffffffffffffe"),
|
||||
"dump unsigned __int128");
|
||||
} else if (btf__find_by_name(btf, "__int128 unsigned") > 0) {
|
||||
TEST_BTF_DUMP_DATA(btf, d, NULL, str, __int128 unsigned, BTF_F_COMPACT,
|
||||
"(__int128 unsigned)0xffffffffffffffff",
|
||||
0xffffffffffffffff);
|
||||
ASSERT_OK(btf_dump_data(btf, d, "__int128 unsigned", NULL, 0, &i, 16, str,
|
||||
"(__int128 unsigned)0xfffffffffffffffffffffffffffffffe"),
|
||||
"dump unsigned __int128");
|
||||
} else {
|
||||
ASSERT_TRUE(false, "unsigned_int128_not_found");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -458,9 +458,9 @@ static int init_prog_array(struct bpf_object *obj, struct bpf_map *prog_array)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "flow_dissector/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "flow_dissector_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (!prog)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -38,10 +38,9 @@ static int create_perf_events(void)
|
||||
|
||||
static void close_perf_events(void)
|
||||
{
|
||||
int cpu = 0;
|
||||
int fd;
|
||||
int cpu, fd;
|
||||
|
||||
while (cpu++ < cpu_cnt) {
|
||||
for (cpu = 0; cpu < cpu_cnt; cpu++) {
|
||||
fd = pfd_array[cpu];
|
||||
if (fd < 0)
|
||||
break;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
void test_probe_user(void)
|
||||
{
|
||||
const char *prog_name = "kprobe/__sys_connect";
|
||||
const char *prog_name = "handle_sys_connect";
|
||||
const char *obj_file = "./test_probe_user.o";
|
||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, );
|
||||
int err, results_map_fd, sock_fd, duration = 0;
|
||||
@@ -18,7 +18,7 @@ void test_probe_user(void)
|
||||
if (!ASSERT_OK_PTR(obj, "obj_open_file"))
|
||||
return;
|
||||
|
||||
kprobe_prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
kprobe_prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK(!kprobe_prog, "find_probe",
|
||||
"prog '%s' not found\n", prog_name))
|
||||
goto cleanup;
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <test_progs.h>
|
||||
|
||||
static void toggle_object_autoload_progs(const struct bpf_object *obj,
|
||||
const char *name_load)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
const char *name = bpf_program__name(prog);
|
||||
|
||||
if (!strcmp(name_load, name))
|
||||
bpf_program__set_autoload(prog, true);
|
||||
else
|
||||
bpf_program__set_autoload(prog, false);
|
||||
}
|
||||
}
|
||||
|
||||
void test_reference_tracking(void)
|
||||
{
|
||||
const char *file = "test_sk_lookup_kern.o";
|
||||
@@ -9,44 +24,49 @@ void test_reference_tracking(void)
|
||||
.object_name = obj_name,
|
||||
.relaxed_maps = true,
|
||||
);
|
||||
struct bpf_object *obj;
|
||||
struct bpf_object *obj_iter, *obj = NULL;
|
||||
struct bpf_program *prog;
|
||||
__u32 duration = 0;
|
||||
int err = 0;
|
||||
|
||||
obj = bpf_object__open_file(file, &open_opts);
|
||||
if (!ASSERT_OK_PTR(obj, "obj_open_file"))
|
||||
obj_iter = bpf_object__open_file(file, &open_opts);
|
||||
if (!ASSERT_OK_PTR(obj_iter, "obj_iter_open_file"))
|
||||
return;
|
||||
|
||||
if (CHECK(strcmp(bpf_object__name(obj), obj_name), "obj_name",
|
||||
if (CHECK(strcmp(bpf_object__name(obj_iter), obj_name), "obj_name",
|
||||
"wrong obj name '%s', expected '%s'\n",
|
||||
bpf_object__name(obj), obj_name))
|
||||
bpf_object__name(obj_iter), obj_name))
|
||||
goto cleanup;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
const char *title;
|
||||
bpf_object__for_each_program(prog, obj_iter) {
|
||||
const char *name;
|
||||
|
||||
/* Ignore .text sections */
|
||||
title = bpf_program__section_name(prog);
|
||||
if (strstr(title, ".text") != NULL)
|
||||
name = bpf_program__name(prog);
|
||||
if (!test__start_subtest(name))
|
||||
continue;
|
||||
|
||||
if (!test__start_subtest(title))
|
||||
continue;
|
||||
obj = bpf_object__open_file(file, &open_opts);
|
||||
if (!ASSERT_OK_PTR(obj, "obj_open_file"))
|
||||
goto cleanup;
|
||||
|
||||
toggle_object_autoload_progs(obj, name);
|
||||
/* Expect verifier failure if test name has 'err' */
|
||||
if (strstr(title, "err_") != NULL) {
|
||||
if (strncmp(name, "err_", sizeof("err_") - 1) == 0) {
|
||||
libbpf_print_fn_t old_print_fn;
|
||||
|
||||
old_print_fn = libbpf_set_print(NULL);
|
||||
err = !bpf_program__load(prog, "GPL", 0);
|
||||
err = !bpf_object__load(obj);
|
||||
libbpf_set_print(old_print_fn);
|
||||
} else {
|
||||
err = bpf_program__load(prog, "GPL", 0);
|
||||
err = bpf_object__load(obj);
|
||||
}
|
||||
CHECK(err, title, "\n");
|
||||
ASSERT_OK(err, name);
|
||||
|
||||
bpf_object__close(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
bpf_object__close(obj);
|
||||
bpf_object__close(obj_iter);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ configure_stack(void)
|
||||
return false;
|
||||
sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
|
||||
"direct-action object-file ./test_sk_assign.o",
|
||||
"section classifier/sk_assign_test",
|
||||
"section tc",
|
||||
(env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
|
||||
if (CHECK(system(tc_cmd), "BPF load failed;",
|
||||
"run with -vv for more info\n"))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <test_progs.h>
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
|
||||
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
enum bpf_prog_type prog_type;
|
||||
@@ -15,23 +15,23 @@ static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
|
||||
return -1;
|
||||
}
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, title);
|
||||
prog = bpf_object__find_program_by_name(obj, name);
|
||||
if (!prog) {
|
||||
log_err("Failed to find %s BPF program", title);
|
||||
log_err("Failed to find %s BPF program", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
|
||||
attach_type, BPF_F_ALLOW_MULTI);
|
||||
if (err) {
|
||||
log_err("Failed to attach %s BPF program", title);
|
||||
log_err("Failed to attach %s BPF program", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title)
|
||||
static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
enum bpf_prog_type prog_type;
|
||||
@@ -42,7 +42,7 @@ static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title)
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, title);
|
||||
prog = bpf_object__find_program_by_name(obj, name);
|
||||
if (!prog)
|
||||
return -1;
|
||||
|
||||
@@ -89,7 +89,7 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
* - child: 0x80 -> 0x90
|
||||
*/
|
||||
|
||||
err = prog_attach(obj, cg_child, "cgroup/getsockopt/child");
|
||||
err = prog_attach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child");
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
@@ -113,7 +113,7 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
* - parent: 0x90 -> 0xA0
|
||||
*/
|
||||
|
||||
err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent");
|
||||
err = prog_attach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent");
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
@@ -157,7 +157,7 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
* - parent: unexpected 0x40, EPERM
|
||||
*/
|
||||
|
||||
err = prog_detach(obj, cg_child, "cgroup/getsockopt/child");
|
||||
err = prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child");
|
||||
if (err) {
|
||||
log_err("Failed to detach child program");
|
||||
goto detach;
|
||||
@@ -198,8 +198,8 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
}
|
||||
|
||||
detach:
|
||||
prog_detach(obj, cg_child, "cgroup/getsockopt/child");
|
||||
prog_detach(obj, cg_parent, "cgroup/getsockopt/parent");
|
||||
prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child");
|
||||
prog_detach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent");
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
|
||||
/* Attach child program and make sure it adds 0x10. */
|
||||
|
||||
err = prog_attach(obj, cg_child, "cgroup/setsockopt");
|
||||
err = prog_attach(obj, cg_child, "cgroup/setsockopt", "_setsockopt");
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
@@ -263,7 +263,7 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
|
||||
/* Attach parent program and make sure it adds another 0x10. */
|
||||
|
||||
err = prog_attach(obj, cg_parent, "cgroup/setsockopt");
|
||||
err = prog_attach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt");
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
@@ -289,8 +289,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
|
||||
}
|
||||
|
||||
detach:
|
||||
prog_detach(obj, cg_child, "cgroup/setsockopt");
|
||||
prog_detach(obj, cg_parent, "cgroup/setsockopt");
|
||||
prog_detach(obj, cg_child, "cgroup/setsockopt", "_setsockopt");
|
||||
prog_detach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ static void test_tailcall_1(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -38,9 +38,9 @@ static void test_tailcall_1(void)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -70,9 +70,9 @@ static void test_tailcall_1(void)
|
||||
err, errno, retval);
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -92,9 +92,9 @@ static void test_tailcall_1(void)
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
j = bpf_map__def(prog_array)->max_entries - 1 - i;
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", j);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", j);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -159,7 +159,7 @@ static void test_tailcall_2(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -176,9 +176,9 @@ static void test_tailcall_2(void)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -233,7 +233,7 @@ static void test_tailcall_count(const char *which)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -249,7 +249,7 @@ static void test_tailcall_count(const char *which)
|
||||
if (CHECK_FAIL(map_fd < 0))
|
||||
goto out;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier/0");
|
||||
prog = bpf_object__find_program_by_name(obj, "classifier_0");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -329,7 +329,7 @@ static void test_tailcall_4(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -354,9 +354,9 @@ static void test_tailcall_4(void)
|
||||
return;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -417,7 +417,7 @@ static void test_tailcall_5(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -442,9 +442,9 @@ static void test_tailcall_5(void)
|
||||
return;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -503,7 +503,7 @@ static void test_tailcall_bpf2bpf_1(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -521,9 +521,9 @@ static void test_tailcall_bpf2bpf_1(void)
|
||||
|
||||
/* nop -> jmp */
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -587,7 +587,7 @@ static void test_tailcall_bpf2bpf_2(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -603,7 +603,7 @@ static void test_tailcall_bpf2bpf_2(void)
|
||||
if (CHECK_FAIL(map_fd < 0))
|
||||
goto out;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier/0");
|
||||
prog = bpf_object__find_program_by_name(obj, "classifier_0");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -665,7 +665,7 @@ static void test_tailcall_bpf2bpf_3(void)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -682,9 +682,9 @@ static void test_tailcall_bpf2bpf_3(void)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -762,7 +762,7 @@ static void test_tailcall_bpf2bpf_4(bool noise)
|
||||
if (CHECK_FAIL(err))
|
||||
return;
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, "classifier");
|
||||
prog = bpf_object__find_program_by_name(obj, "entry");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
@@ -779,9 +779,9 @@ static void test_tailcall_bpf2bpf_4(bool noise)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < bpf_map__def(prog_array)->max_entries; i++) {
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier/%i", i);
|
||||
snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
|
||||
|
||||
prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
void test_trace_printk(void)
|
||||
{
|
||||
int err, iter = 0, duration = 0, found = 0;
|
||||
int err = 0, iter = 0, found = 0;
|
||||
struct trace_printk__bss *bss;
|
||||
struct trace_printk *skel;
|
||||
char *buf = NULL;
|
||||
@@ -18,25 +18,24 @@ void test_trace_printk(void)
|
||||
size_t buflen;
|
||||
|
||||
skel = trace_printk__open();
|
||||
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
|
||||
if (!ASSERT_OK_PTR(skel, "trace_printk__open"))
|
||||
return;
|
||||
|
||||
ASSERT_EQ(skel->rodata->fmt[0], 'T', "invalid printk fmt string");
|
||||
ASSERT_EQ(skel->rodata->fmt[0], 'T', "skel->rodata->fmt[0]");
|
||||
skel->rodata->fmt[0] = 't';
|
||||
|
||||
err = trace_printk__load(skel);
|
||||
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
|
||||
if (!ASSERT_OK(err, "trace_printk__load"))
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
|
||||
err = trace_printk__attach(skel);
|
||||
if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
|
||||
if (!ASSERT_OK(err, "trace_printk__attach"))
|
||||
goto cleanup;
|
||||
|
||||
fp = fopen(TRACEBUF, "r");
|
||||
if (CHECK(fp == NULL, "could not open trace buffer",
|
||||
"error %d opening %s", errno, TRACEBUF))
|
||||
if (!ASSERT_OK_PTR(fp, "fopen(TRACEBUF)"))
|
||||
goto cleanup;
|
||||
|
||||
/* We do not want to wait forever if this test fails... */
|
||||
@@ -46,14 +45,10 @@ void test_trace_printk(void)
|
||||
usleep(1);
|
||||
trace_printk__detach(skel);
|
||||
|
||||
if (CHECK(bss->trace_printk_ran == 0,
|
||||
"bpf_trace_printk never ran",
|
||||
"ran == %d", bss->trace_printk_ran))
|
||||
if (!ASSERT_GT(bss->trace_printk_ran, 0, "bss->trace_printk_ran"))
|
||||
goto cleanup;
|
||||
|
||||
if (CHECK(bss->trace_printk_ret <= 0,
|
||||
"bpf_trace_printk returned <= 0 value",
|
||||
"got %d", bss->trace_printk_ret))
|
||||
if (!ASSERT_GT(bss->trace_printk_ret, 0, "bss->trace_printk_ret"))
|
||||
goto cleanup;
|
||||
|
||||
/* verify our search string is in the trace buffer */
|
||||
@@ -66,8 +61,7 @@ void test_trace_printk(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (CHECK(!found, "message from bpf_trace_printk not found",
|
||||
"no instance of %s in %s", SEARCHMSG, TRACEBUF))
|
||||
if (!ASSERT_EQ(found, bss->trace_printk_ran, "found"))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
|
||||
#include <test_progs.h>
|
||||
|
||||
#include "trace_vprintk.lskel.h"
|
||||
|
||||
#define TRACEBUF "/sys/kernel/debug/tracing/trace_pipe"
|
||||
#define SEARCHMSG "1,2,3,4,5,6,7,8,9,10"
|
||||
|
||||
void test_trace_vprintk(void)
|
||||
{
|
||||
int err = 0, iter = 0, found = 0;
|
||||
struct trace_vprintk__bss *bss;
|
||||
struct trace_vprintk *skel;
|
||||
char *buf = NULL;
|
||||
FILE *fp = NULL;
|
||||
size_t buflen;
|
||||
|
||||
skel = trace_vprintk__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "trace_vprintk__open_and_load"))
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
|
||||
err = trace_vprintk__attach(skel);
|
||||
if (!ASSERT_OK(err, "trace_vprintk__attach"))
|
||||
goto cleanup;
|
||||
|
||||
fp = fopen(TRACEBUF, "r");
|
||||
if (!ASSERT_OK_PTR(fp, "fopen(TRACEBUF)"))
|
||||
goto cleanup;
|
||||
|
||||
/* We do not want to wait forever if this test fails... */
|
||||
fcntl(fileno(fp), F_SETFL, O_NONBLOCK);
|
||||
|
||||
/* wait for tracepoint to trigger */
|
||||
usleep(1);
|
||||
trace_vprintk__detach(skel);
|
||||
|
||||
if (!ASSERT_GT(bss->trace_vprintk_ran, 0, "bss->trace_vprintk_ran"))
|
||||
goto cleanup;
|
||||
|
||||
if (!ASSERT_GT(bss->trace_vprintk_ret, 0, "bss->trace_vprintk_ret"))
|
||||
goto cleanup;
|
||||
|
||||
/* verify our search string is in the trace buffer */
|
||||
while (getline(&buf, &buflen, fp) >= 0 || errno == EAGAIN) {
|
||||
if (strstr(buf, SEARCHMSG) != NULL)
|
||||
found++;
|
||||
if (found == bss->trace_vprintk_ran)
|
||||
break;
|
||||
if (++iter > 1000)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ASSERT_EQ(found, bss->trace_vprintk_ran, "found"))
|
||||
goto cleanup;
|
||||
|
||||
if (!ASSERT_LT(bss->null_data_vprintk_ret, 0, "bss->null_data_vprintk_ret"))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
trace_vprintk__destroy(skel);
|
||||
free(buf);
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
|
||||
#include "test_progs.h"
|
||||
#include "xdpwall.skel.h"
|
||||
|
||||
void test_xdpwall(void)
|
||||
{
|
||||
struct xdpwall *skel;
|
||||
|
||||
skel = xdpwall__open_and_load();
|
||||
ASSERT_OK_PTR(skel, "Does LLMV have https://reviews.llvm.org/D109073?");
|
||||
|
||||
xdpwall__destroy(skel);
|
||||
}
|
||||
@@ -19,9 +19,8 @@
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
#define PROG(F) PROG_(F, _##F)
|
||||
#define PROG_(NUM, NAME) SEC("flow_dissector/"#NUM) int bpf_func##NAME
|
||||
#define PROG_(NUM, NAME) SEC("flow_dissector") int flow_dissector_##NUM
|
||||
|
||||
/* These are the identifiers of the BPF programs that will be used in tail
|
||||
* calls. Name is limited to 16 characters, with the terminating character and
|
||||
|
||||
@@ -20,7 +20,7 @@ struct {
|
||||
|
||||
__u32 invocations = 0;
|
||||
|
||||
SEC("cgroup_skb/egress/1")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress1(struct __sk_buff *skb)
|
||||
{
|
||||
struct cgroup_value *ptr_cg_storage =
|
||||
@@ -32,7 +32,7 @@ int egress1(struct __sk_buff *skb)
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("cgroup_skb/egress/2")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress2(struct __sk_buff *skb)
|
||||
{
|
||||
struct cgroup_value *ptr_cg_storage =
|
||||
|
||||
@@ -20,7 +20,7 @@ struct {
|
||||
|
||||
__u32 invocations = 0;
|
||||
|
||||
SEC("cgroup_skb/egress/1")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress1(struct __sk_buff *skb)
|
||||
{
|
||||
struct cgroup_value *ptr_cg_storage =
|
||||
@@ -32,7 +32,7 @@ int egress1(struct __sk_buff *skb)
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("cgroup_skb/egress/2")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress2(struct __sk_buff *skb)
|
||||
{
|
||||
struct cgroup_value *ptr_cg_storage =
|
||||
|
||||
@@ -47,7 +47,7 @@ check_percpu_elem(struct bpf_map *map, __u32 *key, __u64 *val,
|
||||
|
||||
u32 arraymap_output = 0;
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int test_pkt_access(struct __sk_buff *skb)
|
||||
{
|
||||
struct callback_ctx data;
|
||||
|
||||
@@ -78,7 +78,7 @@ int hashmap_output = 0;
|
||||
int hashmap_elems = 0;
|
||||
int percpu_map_elems = 0;
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int test_pkt_access(struct __sk_buff *skb)
|
||||
{
|
||||
struct callback_ctx data;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
char _license[] SEC("license") = "GPL";
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} perf_buf_map SEC(".maps");
|
||||
|
||||
#define _(P) (__builtin_preserve_access_index(P))
|
||||
|
||||
@@ -8,7 +8,7 @@ extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym;
|
||||
extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b,
|
||||
__u32 c, __u64 d) __ksym;
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int kfunc_call_test2(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock *sk = skb->sk;
|
||||
@@ -23,7 +23,7 @@ int kfunc_call_test2(struct __sk_buff *skb)
|
||||
return bpf_kfunc_call_test2((struct sock *)sk, 1, 2);
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int kfunc_call_test1(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock *sk = skb->sk;
|
||||
|
||||
@@ -33,7 +33,7 @@ int __noinline f1(struct __sk_buff *skb)
|
||||
return (__u32)bpf_kfunc_call_test1((struct sock *)sk, 1, 2, 3, 4);
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int kfunc_call_test1(struct __sk_buff *skb)
|
||||
{
|
||||
return f1(skb);
|
||||
|
||||
@@ -11,8 +11,8 @@ typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH];
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
|
||||
__uint(max_entries, 16384);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(stack_trace_t));
|
||||
__type(key, __u32);
|
||||
__type(value, stack_trace_t);
|
||||
} stackmap SEC(".maps");
|
||||
|
||||
struct {
|
||||
|
||||
@@ -25,7 +25,7 @@ out:
|
||||
return ip;
|
||||
}
|
||||
|
||||
SEC("classifier/cls")
|
||||
SEC("tc")
|
||||
int main_prog(struct __sk_buff *skb)
|
||||
{
|
||||
struct iphdr *ip = NULL;
|
||||
|
||||
@@ -7,22 +7,22 @@ int _version SEC("version") = 1;
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_SOCKMAP);
|
||||
__uint(max_entries, 20);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} sock_map_rx SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_SOCKMAP);
|
||||
__uint(max_entries, 20);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} sock_map_tx SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_SOCKMAP);
|
||||
__uint(max_entries, 20);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} sock_map_msg SEC(".maps");
|
||||
|
||||
struct {
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
__u32 _version SEC("version") = 1;
|
||||
|
||||
SEC("cgroup/getsockopt/child")
|
||||
SEC("cgroup/getsockopt")
|
||||
int _getsockopt_child(struct bpf_sockopt *ctx)
|
||||
{
|
||||
__u8 *optval_end = ctx->optval_end;
|
||||
@@ -29,7 +28,7 @@ int _getsockopt_child(struct bpf_sockopt *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("cgroup/getsockopt/parent")
|
||||
SEC("cgroup/getsockopt")
|
||||
int _getsockopt_parent(struct bpf_sockopt *ctx)
|
||||
{
|
||||
__u8 *optval_end = ctx->optval_end;
|
||||
|
||||
@@ -11,8 +11,8 @@ struct {
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
#define TAIL_FUNC(x) \
|
||||
SEC("classifier/" #x) \
|
||||
int bpf_func_##x(struct __sk_buff *skb) \
|
||||
SEC("tc") \
|
||||
int classifier_##x(struct __sk_buff *skb) \
|
||||
{ \
|
||||
return x; \
|
||||
}
|
||||
@@ -20,7 +20,7 @@ TAIL_FUNC(0)
|
||||
TAIL_FUNC(1)
|
||||
TAIL_FUNC(2)
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
/* Multiple locations to make sure we patch
|
||||
@@ -45,4 +45,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -10,41 +10,41 @@ struct {
|
||||
__uint(value_size, sizeof(__u32));
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/1")
|
||||
int bpf_func_1(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_1(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("classifier/2")
|
||||
int bpf_func_2(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_2(struct __sk_buff *skb)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
SEC("classifier/3")
|
||||
int bpf_func_3(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_3(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 4);
|
||||
return 3;
|
||||
}
|
||||
|
||||
SEC("classifier/4")
|
||||
int bpf_func_4(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_4(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 3);
|
||||
return 4;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
@@ -56,4 +56,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -12,15 +12,15 @@ struct {
|
||||
|
||||
int count = 0;
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
count++;
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
@@ -28,4 +28,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -13,8 +13,8 @@ struct {
|
||||
int selector = 0;
|
||||
|
||||
#define TAIL_FUNC(x) \
|
||||
SEC("classifier/" #x) \
|
||||
int bpf_func_##x(struct __sk_buff *skb) \
|
||||
SEC("tc") \
|
||||
int classifier_##x(struct __sk_buff *skb) \
|
||||
{ \
|
||||
return x; \
|
||||
}
|
||||
@@ -22,7 +22,7 @@ TAIL_FUNC(0)
|
||||
TAIL_FUNC(1)
|
||||
TAIL_FUNC(2)
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call(skb, &jmp_table, selector);
|
||||
@@ -30,4 +30,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -13,8 +13,8 @@ struct {
|
||||
int selector = 0;
|
||||
|
||||
#define TAIL_FUNC(x) \
|
||||
SEC("classifier/" #x) \
|
||||
int bpf_func_##x(struct __sk_buff *skb) \
|
||||
SEC("tc") \
|
||||
int classifier_##x(struct __sk_buff *skb) \
|
||||
{ \
|
||||
return x; \
|
||||
}
|
||||
@@ -22,7 +22,7 @@ TAIL_FUNC(0)
|
||||
TAIL_FUNC(1)
|
||||
TAIL_FUNC(2)
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
int idx = 0;
|
||||
@@ -37,4 +37,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -12,8 +12,8 @@ struct {
|
||||
|
||||
int count, which;
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
count++;
|
||||
if (__builtin_constant_p(which))
|
||||
@@ -22,7 +22,7 @@ int bpf_func_0(struct __sk_buff *skb)
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
if (__builtin_constant_p(which))
|
||||
|
||||
@@ -10,8 +10,8 @@ struct {
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
#define TAIL_FUNC(x) \
|
||||
SEC("classifier/" #x) \
|
||||
int bpf_func_##x(struct __sk_buff *skb) \
|
||||
SEC("tc") \
|
||||
int classifier_##x(struct __sk_buff *skb) \
|
||||
{ \
|
||||
return x; \
|
||||
}
|
||||
@@ -26,7 +26,7 @@ int subprog_tail(struct __sk_buff *skb)
|
||||
return skb->len * 2;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 1);
|
||||
@@ -35,4 +35,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -22,14 +22,14 @@ int subprog_tail(struct __sk_buff *skb)
|
||||
|
||||
int count = 0;
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
count++;
|
||||
return subprog_tail(skb);
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
@@ -38,4 +38,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -33,23 +33,23 @@ int subprog_tail(struct __sk_buff *skb)
|
||||
return skb->len * 2;
|
||||
}
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
volatile char arr[128] = {};
|
||||
|
||||
return subprog_tail2(skb);
|
||||
}
|
||||
|
||||
SEC("classifier/1")
|
||||
int bpf_func_1(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_1(struct __sk_buff *skb)
|
||||
{
|
||||
volatile char arr[128] = {};
|
||||
|
||||
return skb->len * 3;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
volatile char arr[128] = {};
|
||||
@@ -58,4 +58,3 @@ int entry(struct __sk_buff *skb)
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -50,30 +50,29 @@ int subprog_tail(struct __sk_buff *skb)
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
SEC("classifier/1")
|
||||
int bpf_func_1(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_1(struct __sk_buff *skb)
|
||||
{
|
||||
return subprog_tail_2(skb);
|
||||
}
|
||||
|
||||
SEC("classifier/2")
|
||||
int bpf_func_2(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_2(struct __sk_buff *skb)
|
||||
{
|
||||
count++;
|
||||
return subprog_tail_2(skb);
|
||||
}
|
||||
|
||||
SEC("classifier/0")
|
||||
int bpf_func_0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
return subprog_tail_1(skb);
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
return subprog_tail(skb);
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -21,8 +21,8 @@ struct inner_map_sz2 {
|
||||
struct outer_arr {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 3);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
/* it's possible to use anonymous struct as inner map definition here */
|
||||
__array(values, struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
@@ -61,8 +61,8 @@ struct inner_map_sz4 {
|
||||
struct outer_arr_dyn {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 3);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
__array(values, struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(map_flags, BPF_F_INNER_MAP);
|
||||
@@ -81,7 +81,7 @@ struct outer_arr_dyn {
|
||||
struct outer_hash {
|
||||
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
|
||||
__uint(max_entries, 5);
|
||||
__uint(key_size, sizeof(int));
|
||||
__type(key, int);
|
||||
/* Here everything works flawlessly due to reuse of struct inner_map
|
||||
* and compiler will complain at the attempt to use non-inner_map
|
||||
* references below. This is great experience.
|
||||
@@ -111,8 +111,8 @@ struct sockarr_sz2 {
|
||||
struct outer_sockarr_sz1 {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
__array(values, struct sockarr_sz1);
|
||||
} outer_sockarr SEC(".maps") = {
|
||||
.values = { (void *)&sockarr_sz1 },
|
||||
|
||||
@@ -145,7 +145,7 @@ release:
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("classifier/ingress")
|
||||
SEC("tc")
|
||||
int cls_ingress(struct __sk_buff *skb)
|
||||
{
|
||||
struct ipv6hdr *ip6h;
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
int calls = 0;
|
||||
int alt_calls = 0;
|
||||
|
||||
SEC("cgroup_skb/egress1")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress(struct __sk_buff *skb)
|
||||
{
|
||||
__sync_fetch_and_add(&calls, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("cgroup_skb/egress2")
|
||||
SEC("cgroup_skb/egress")
|
||||
int egress_alt(struct __sk_buff *skb)
|
||||
{
|
||||
__sync_fetch_and_add(&alt_calls, 1);
|
||||
|
||||
@@ -153,7 +153,7 @@ int xdp_input_len_exceed(struct xdp_md *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_use_helper(struct __sk_buff *ctx)
|
||||
{
|
||||
int retval = BPF_OK; /* Expected retval on successful test */
|
||||
@@ -172,7 +172,7 @@ out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_exceed_mtu(struct __sk_buff *ctx)
|
||||
{
|
||||
__u32 ifindex = GLOBAL_USER_IFINDEX;
|
||||
@@ -196,7 +196,7 @@ int tc_exceed_mtu(struct __sk_buff *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_exceed_mtu_da(struct __sk_buff *ctx)
|
||||
{
|
||||
/* SKB Direct-Access variant */
|
||||
@@ -223,7 +223,7 @@ int tc_exceed_mtu_da(struct __sk_buff *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_minus_delta(struct __sk_buff *ctx)
|
||||
{
|
||||
int retval = BPF_OK; /* Expected retval on successful test */
|
||||
@@ -245,7 +245,7 @@ int tc_minus_delta(struct __sk_buff *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_input_len(struct __sk_buff *ctx)
|
||||
{
|
||||
int retval = BPF_OK; /* Expected retval on successful test */
|
||||
@@ -265,7 +265,7 @@ int tc_input_len(struct __sk_buff *ctx)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int tc_input_len_exceed(struct __sk_buff *ctx)
|
||||
{
|
||||
int retval = BPF_DROP; /* Fail */
|
||||
|
||||
@@ -928,7 +928,7 @@ static INLINING verdict_t process_ipv6(buf_t *pkt, metrics_t *metrics)
|
||||
}
|
||||
}
|
||||
|
||||
SEC("classifier/cls_redirect")
|
||||
SEC("tc")
|
||||
int cls_redirect(struct __sk_buff *skb)
|
||||
{
|
||||
metrics_t *metrics = get_global_metrics();
|
||||
|
||||
@@ -68,7 +68,7 @@ static struct foo struct3 = {
|
||||
bpf_map_update_elem(&result_##map, &key, var, 0); \
|
||||
} while (0)
|
||||
|
||||
SEC("classifier/static_data_load")
|
||||
SEC("tc")
|
||||
int load_static_data(struct __sk_buff *skb)
|
||||
{
|
||||
static const __u64 bar = ~0;
|
||||
|
||||
@@ -38,7 +38,7 @@ int f3(int val, struct __sk_buff *skb, int var)
|
||||
return skb->ifindex * val * var;
|
||||
}
|
||||
|
||||
SEC("classifier/test")
|
||||
SEC("tc")
|
||||
int test_cls(struct __sk_buff *skb)
|
||||
{
|
||||
return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4);
|
||||
|
||||
@@ -54,7 +54,7 @@ int f8(struct __sk_buff *skb)
|
||||
}
|
||||
#endif
|
||||
|
||||
SEC("classifier/test")
|
||||
SEC("tc")
|
||||
int test_cls(struct __sk_buff *skb)
|
||||
{
|
||||
#ifndef NO_FN8
|
||||
|
||||
@@ -24,7 +24,7 @@ int f3(int val, struct __sk_buff *skb)
|
||||
return skb->ifindex * val;
|
||||
}
|
||||
|
||||
SEC("classifier/test")
|
||||
SEC("tc")
|
||||
int test_cls(struct __sk_buff *skb)
|
||||
{
|
||||
return f1(skb) + f2(2, skb) + f3(3, skb);
|
||||
|
||||
@@ -24,7 +24,7 @@ int f3(int val, struct __sk_buff *skb)
|
||||
return skb->ifindex * val;
|
||||
}
|
||||
|
||||
SEC("classifier/test")
|
||||
SEC("tc")
|
||||
int test_cls(struct __sk_buff *skb)
|
||||
{
|
||||
return f1(skb) + f2(2, skb) + f3(3, skb);
|
||||
|
||||
@@ -10,7 +10,7 @@ void foo(struct __sk_buff *skb)
|
||||
skb->tc_index = 0;
|
||||
}
|
||||
|
||||
SEC("classifier/test")
|
||||
SEC("tc")
|
||||
int test_cls(struct __sk_buff *skb)
|
||||
{
|
||||
foo(skb);
|
||||
|
||||
@@ -9,21 +9,19 @@ struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, 0);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
/* must be sizeof(__u32) for map in map */
|
||||
__uint(value_size, sizeof(__u32));
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} mim_array SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, 0);
|
||||
__uint(key_size, sizeof(int));
|
||||
/* must be sizeof(__u32) for map in map */
|
||||
__uint(value_size, sizeof(__u32));
|
||||
__type(key, int);
|
||||
__type(value, __u32);
|
||||
} mim_hash SEC(".maps");
|
||||
|
||||
SEC("xdp_mimtest")
|
||||
SEC("xdp")
|
||||
int xdp_mimtest0(struct xdp_md *ctx)
|
||||
{
|
||||
int value = 123;
|
||||
|
||||
@@ -13,7 +13,7 @@ struct inner {
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 0); /* This will make map creation to fail */
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__type(key, __u32);
|
||||
__array(values, struct inner);
|
||||
} mim SEC(".maps");
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ static int handle_passive_estab(struct bpf_sock_ops *skops)
|
||||
return check_active_hdr_in(skops);
|
||||
}
|
||||
|
||||
SEC("sockops/misc_estab")
|
||||
SEC("sockops")
|
||||
int misc_estab(struct bpf_sock_ops *skops)
|
||||
{
|
||||
int true_val = 1;
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} array_1 SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
__uint(map_flags, BPF_F_PRESERVE_ELEMS);
|
||||
} array_2 SEC(".maps");
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} perf_buf_map SEC(".maps");
|
||||
|
||||
SEC("tp/raw_syscalls/sys_enter")
|
||||
|
||||
@@ -97,7 +97,7 @@ int test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/test_pkt_access")
|
||||
SEC("tc")
|
||||
int test_pkt_access(struct __sk_buff *skb)
|
||||
{
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define TEST_FIELD(TYPE, FIELD, MASK) \
|
||||
{ \
|
||||
@@ -27,7 +25,7 @@ int _version SEC("version") = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
SEC("classifier/test_pkt_md_access")
|
||||
SEC("tc")
|
||||
int test_pkt_md_access(struct __sk_buff *skb)
|
||||
{
|
||||
TEST_FIELD(__u8, len, 0xFF);
|
||||
|
||||
@@ -8,13 +8,37 @@
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#if defined(__TARGET_ARCH_x86)
|
||||
#define SYSCALL_WRAPPER 1
|
||||
#define SYS_PREFIX "__x64_"
|
||||
#elif defined(__TARGET_ARCH_s390)
|
||||
#define SYSCALL_WRAPPER 1
|
||||
#define SYS_PREFIX "__s390x_"
|
||||
#elif defined(__TARGET_ARCH_arm64)
|
||||
#define SYSCALL_WRAPPER 1
|
||||
#define SYS_PREFIX "__arm64_"
|
||||
#else
|
||||
#define SYSCALL_WRAPPER 0
|
||||
#define SYS_PREFIX ""
|
||||
#endif
|
||||
|
||||
static struct sockaddr_in old;
|
||||
|
||||
SEC("kprobe/__sys_connect")
|
||||
SEC("kprobe/" SYS_PREFIX "sys_connect")
|
||||
int BPF_KPROBE(handle_sys_connect)
|
||||
{
|
||||
void *ptr = (void *)PT_REGS_PARM2(ctx);
|
||||
#if SYSCALL_WRAPPER == 1
|
||||
struct pt_regs *real_regs;
|
||||
#endif
|
||||
struct sockaddr_in new;
|
||||
void *ptr;
|
||||
|
||||
#if SYSCALL_WRAPPER == 0
|
||||
ptr = (void *)PT_REGS_PARM2(ctx);
|
||||
#else
|
||||
real_regs = (struct pt_regs *)PT_REGS_PARM1(ctx);
|
||||
bpf_probe_read_kernel(&ptr, sizeof(ptr), &PT_REGS_PARM2(real_regs));
|
||||
#endif
|
||||
|
||||
bpf_probe_read_user(&old, sizeof(old), ptr);
|
||||
__builtin_memset(&new, 0xab, sizeof(new));
|
||||
|
||||
@@ -24,8 +24,8 @@ int _version SEC("version") = 1;
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(__u32));
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} outer_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
|
||||
@@ -36,7 +36,6 @@ struct {
|
||||
.pinning = PIN_GLOBAL_NS,
|
||||
};
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
/* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */
|
||||
@@ -159,7 +158,7 @@ assign:
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("classifier/sk_assign_test")
|
||||
SEC("tc")
|
||||
int bpf_sk_assign_test(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple *tuple, ln = {0};
|
||||
|
||||
@@ -72,32 +72,32 @@ static const __u16 DST_PORT = 7007; /* Host byte order */
|
||||
static const __u32 DST_IP4 = IP4(127, 0, 0, 1);
|
||||
static const __u32 DST_IP6[] = IP6(0xfd000000, 0x0, 0x0, 0x00000001);
|
||||
|
||||
SEC("sk_lookup/lookup_pass")
|
||||
SEC("sk_lookup")
|
||||
int lookup_pass(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/lookup_drop")
|
||||
SEC("sk_lookup")
|
||||
int lookup_drop(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
return SK_DROP;
|
||||
}
|
||||
|
||||
SEC("sk_reuseport/reuse_pass")
|
||||
SEC("sk_reuseport")
|
||||
int reuseport_pass(struct sk_reuseport_md *ctx)
|
||||
{
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_reuseport/reuse_drop")
|
||||
SEC("sk_reuseport")
|
||||
int reuseport_drop(struct sk_reuseport_md *ctx)
|
||||
{
|
||||
return SK_DROP;
|
||||
}
|
||||
|
||||
/* Redirect packets destined for port DST_PORT to socket at redir_map[0]. */
|
||||
SEC("sk_lookup/redir_port")
|
||||
SEC("sk_lookup")
|
||||
int redir_port(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -116,7 +116,7 @@ int redir_port(struct bpf_sk_lookup *ctx)
|
||||
}
|
||||
|
||||
/* Redirect packets destined for DST_IP4 address to socket at redir_map[0]. */
|
||||
SEC("sk_lookup/redir_ip4")
|
||||
SEC("sk_lookup")
|
||||
int redir_ip4(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -139,7 +139,7 @@ int redir_ip4(struct bpf_sk_lookup *ctx)
|
||||
}
|
||||
|
||||
/* Redirect packets destined for DST_IP6 address to socket at redir_map[0]. */
|
||||
SEC("sk_lookup/redir_ip6")
|
||||
SEC("sk_lookup")
|
||||
int redir_ip6(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -164,7 +164,7 @@ int redir_ip6(struct bpf_sk_lookup *ctx)
|
||||
return err ? SK_DROP : SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/select_sock_a")
|
||||
SEC("sk_lookup")
|
||||
int select_sock_a(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -179,7 +179,7 @@ int select_sock_a(struct bpf_sk_lookup *ctx)
|
||||
return err ? SK_DROP : SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/select_sock_a_no_reuseport")
|
||||
SEC("sk_lookup")
|
||||
int select_sock_a_no_reuseport(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -194,7 +194,7 @@ int select_sock_a_no_reuseport(struct bpf_sk_lookup *ctx)
|
||||
return err ? SK_DROP : SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_reuseport/select_sock_b")
|
||||
SEC("sk_reuseport")
|
||||
int select_sock_b(struct sk_reuseport_md *ctx)
|
||||
{
|
||||
__u32 key = KEY_SERVER_B;
|
||||
@@ -205,7 +205,7 @@ int select_sock_b(struct sk_reuseport_md *ctx)
|
||||
}
|
||||
|
||||
/* Check that bpf_sk_assign() returns -EEXIST if socket already selected. */
|
||||
SEC("sk_lookup/sk_assign_eexist")
|
||||
SEC("sk_lookup")
|
||||
int sk_assign_eexist(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -238,7 +238,7 @@ out:
|
||||
}
|
||||
|
||||
/* Check that bpf_sk_assign(BPF_SK_LOOKUP_F_REPLACE) can override selection. */
|
||||
SEC("sk_lookup/sk_assign_replace_flag")
|
||||
SEC("sk_lookup")
|
||||
int sk_assign_replace_flag(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -270,7 +270,7 @@ out:
|
||||
}
|
||||
|
||||
/* Check that bpf_sk_assign(sk=NULL) is accepted. */
|
||||
SEC("sk_lookup/sk_assign_null")
|
||||
SEC("sk_lookup")
|
||||
int sk_assign_null(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk = NULL;
|
||||
@@ -313,7 +313,7 @@ out:
|
||||
}
|
||||
|
||||
/* Check that selected sk is accessible through context. */
|
||||
SEC("sk_lookup/access_ctx_sk")
|
||||
SEC("sk_lookup")
|
||||
int access_ctx_sk(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk1 = NULL, *sk2 = NULL;
|
||||
@@ -379,7 +379,7 @@ out:
|
||||
* are not covered because they give bogus results, that is the
|
||||
* verifier ignores the offset.
|
||||
*/
|
||||
SEC("sk_lookup/ctx_narrow_access")
|
||||
SEC("sk_lookup")
|
||||
int ctx_narrow_access(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -553,7 +553,7 @@ int ctx_narrow_access(struct bpf_sk_lookup *ctx)
|
||||
}
|
||||
|
||||
/* Check that sk_assign rejects SERVER_A socket with -ESOCKNOSUPPORT */
|
||||
SEC("sk_lookup/sk_assign_esocknosupport")
|
||||
SEC("sk_lookup")
|
||||
int sk_assign_esocknosupport(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
@@ -578,28 +578,28 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_pass1")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_pass1(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_pass2")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_pass2(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_drop1")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_drop1(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
|
||||
return SK_DROP;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_drop2")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_drop2(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
|
||||
@@ -623,7 +623,7 @@ static __always_inline int select_server_a(struct bpf_sk_lookup *ctx)
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_redir1")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_redir1(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
int ret;
|
||||
@@ -633,7 +633,7 @@ int multi_prog_redir1(struct bpf_sk_lookup *ctx)
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_lookup/multi_prog_redir2")
|
||||
SEC("sk_lookup")
|
||||
int multi_prog_redir2(struct bpf_sk_lookup *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
/* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */
|
||||
@@ -53,8 +52,8 @@ static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off,
|
||||
return result;
|
||||
}
|
||||
|
||||
SEC("classifier/sk_lookup_success")
|
||||
int bpf_sk_lookup_test0(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int sk_lookup_success(struct __sk_buff *skb)
|
||||
{
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
void *data = (void *)(long)skb->data;
|
||||
@@ -79,8 +78,8 @@ int bpf_sk_lookup_test0(struct __sk_buff *skb)
|
||||
return sk ? TC_ACT_OK : TC_ACT_UNSPEC;
|
||||
}
|
||||
|
||||
SEC("classifier/sk_lookup_success_simple")
|
||||
int bpf_sk_lookup_test1(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int sk_lookup_success_simple(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -91,8 +90,8 @@ int bpf_sk_lookup_test1(struct __sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/err_use_after_free")
|
||||
int bpf_sk_lookup_uaf(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_use_after_free(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -106,8 +105,8 @@ int bpf_sk_lookup_uaf(struct __sk_buff *skb)
|
||||
return family;
|
||||
}
|
||||
|
||||
SEC("classifier/err_modify_sk_pointer")
|
||||
int bpf_sk_lookup_modptr(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_modify_sk_pointer(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -121,8 +120,8 @@ int bpf_sk_lookup_modptr(struct __sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/err_modify_sk_or_null_pointer")
|
||||
int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_modify_sk_or_null_pointer(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -135,8 +134,8 @@ int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/err_no_release")
|
||||
int bpf_sk_lookup_test2(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_no_release(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
|
||||
@@ -144,8 +143,8 @@ int bpf_sk_lookup_test2(struct __sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/err_release_twice")
|
||||
int bpf_sk_lookup_test3(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_release_twice(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -156,8 +155,8 @@ int bpf_sk_lookup_test3(struct __sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/err_release_unchecked")
|
||||
int bpf_sk_lookup_test4(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_release_unchecked(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_sock_tuple tuple = {};
|
||||
struct bpf_sock *sk;
|
||||
@@ -173,8 +172,8 @@ void lookup_no_release(struct __sk_buff *skb)
|
||||
bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0);
|
||||
}
|
||||
|
||||
SEC("classifier/err_no_release_subcall")
|
||||
int bpf_sk_lookup_test5(struct __sk_buff *skb)
|
||||
SEC("tc")
|
||||
int err_no_release_subcall(struct __sk_buff *skb)
|
||||
{
|
||||
lookup_no_release(skb);
|
||||
return 0;
|
||||
|
||||
@@ -14,7 +14,7 @@ struct {
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("classifier/test_skb_helpers")
|
||||
SEC("tc")
|
||||
int test_skb_helpers(struct __sk_buff *skb)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
@@ -56,7 +56,7 @@ int prog_stream_verdict(struct __sk_buff *skb)
|
||||
return verdict;
|
||||
}
|
||||
|
||||
SEC("sk_skb/skb_verdict")
|
||||
SEC("sk_skb")
|
||||
int prog_skb_verdict(struct __sk_buff *skb)
|
||||
{
|
||||
unsigned int *count;
|
||||
|
||||
@@ -9,7 +9,7 @@ struct {
|
||||
__type(value, __u64);
|
||||
} sock_map SEC(".maps");
|
||||
|
||||
SEC("sk_skb/skb_verdict")
|
||||
SEC("sk_skb")
|
||||
int prog_skb_verdict(struct __sk_buff *skb)
|
||||
{
|
||||
return SK_DROP;
|
||||
|
||||
@@ -24,7 +24,7 @@ struct {
|
||||
__type(value, __u64);
|
||||
} dst_sock_hash SEC(".maps");
|
||||
|
||||
SEC("classifier/copy_sock_map")
|
||||
SEC("tc")
|
||||
int copy_sock_map(void *ctx)
|
||||
{
|
||||
struct bpf_sock *sk;
|
||||
|
||||
@@ -28,8 +28,8 @@ struct {
|
||||
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
|
||||
__uint(max_entries, 128);
|
||||
__uint(map_flags, BPF_F_STACK_BUILD_ID);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(stack_trace_t));
|
||||
__type(key, __u32);
|
||||
__type(value, stack_trace_t);
|
||||
} stackmap SEC(".maps");
|
||||
|
||||
struct {
|
||||
|
||||
@@ -27,8 +27,8 @@ typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH];
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
|
||||
__uint(max_entries, 16384);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(stack_trace_t));
|
||||
__type(key, __u32);
|
||||
__type(value, stack_trace_t);
|
||||
} stackmap SEC(".maps");
|
||||
|
||||
struct {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/* Dummy prog to test TC-BPF API */
|
||||
|
||||
SEC("classifier")
|
||||
SEC("tc")
|
||||
int cls(struct __sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -70,7 +70,7 @@ static __always_inline bool is_remote_ep_v6(struct __sk_buff *skb,
|
||||
return v6_equal(ip6h->daddr, addr);
|
||||
}
|
||||
|
||||
SEC("classifier/chk_egress")
|
||||
SEC("tc")
|
||||
int tc_chk(struct __sk_buff *skb)
|
||||
{
|
||||
void *data_end = ctx_ptr(skb->data_end);
|
||||
@@ -83,7 +83,7 @@ int tc_chk(struct __sk_buff *skb)
|
||||
return !raw[0] && !raw[1] && !raw[2] ? TC_ACT_SHOT : TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("classifier/dst_ingress")
|
||||
SEC("tc")
|
||||
int tc_dst(struct __sk_buff *skb)
|
||||
{
|
||||
__u8 zero[ETH_ALEN * 2];
|
||||
@@ -108,7 +108,7 @@ int tc_dst(struct __sk_buff *skb)
|
||||
return bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0);
|
||||
}
|
||||
|
||||
SEC("classifier/src_ingress")
|
||||
SEC("tc")
|
||||
int tc_src(struct __sk_buff *skb)
|
||||
{
|
||||
__u8 zero[ETH_ALEN * 2];
|
||||
|
||||
@@ -75,7 +75,7 @@ static __always_inline int fill_fib_params_v6(struct __sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("classifier/chk_egress")
|
||||
SEC("tc")
|
||||
int tc_chk(struct __sk_buff *skb)
|
||||
{
|
||||
void *data_end = ctx_ptr(skb->data_end);
|
||||
@@ -143,13 +143,13 @@ static __always_inline int tc_redir(struct __sk_buff *skb)
|
||||
/* these are identical, but keep them separate for compatibility with the
|
||||
* section names expected by test_tc_redirect.sh
|
||||
*/
|
||||
SEC("classifier/dst_ingress")
|
||||
SEC("tc")
|
||||
int tc_dst(struct __sk_buff *skb)
|
||||
{
|
||||
return tc_redir(skb);
|
||||
}
|
||||
|
||||
SEC("classifier/src_ingress")
|
||||
SEC("tc")
|
||||
int tc_src(struct __sk_buff *skb)
|
||||
{
|
||||
return tc_redir(skb);
|
||||
|
||||
@@ -16,31 +16,31 @@ volatile const __u32 IFINDEX_DST;
|
||||
static const __u8 src_mac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
||||
static const __u8 dst_mac[] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
|
||||
SEC("classifier/chk_egress")
|
||||
SEC("tc")
|
||||
int tc_chk(struct __sk_buff *skb)
|
||||
{
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
SEC("classifier/dst_ingress")
|
||||
SEC("tc")
|
||||
int tc_dst(struct __sk_buff *skb)
|
||||
{
|
||||
return bpf_redirect_peer(IFINDEX_SRC, 0);
|
||||
}
|
||||
|
||||
SEC("classifier/src_ingress")
|
||||
SEC("tc")
|
||||
int tc_src(struct __sk_buff *skb)
|
||||
{
|
||||
return bpf_redirect_peer(IFINDEX_DST, 0);
|
||||
}
|
||||
|
||||
SEC("classifier/dst_ingress_l3")
|
||||
SEC("tc")
|
||||
int tc_dst_l3(struct __sk_buff *skb)
|
||||
{
|
||||
return bpf_redirect(IFINDEX_SRC, 0);
|
||||
}
|
||||
|
||||
SEC("classifier/src_ingress_l3")
|
||||
SEC("tc")
|
||||
int tc_src_l3(struct __sk_buff *skb)
|
||||
{
|
||||
__u16 proto = skb->protocol;
|
||||
|
||||
@@ -148,7 +148,7 @@ release:
|
||||
bpf_sk_release(sk);
|
||||
}
|
||||
|
||||
SEC("clsact/check_syncookie")
|
||||
SEC("tc")
|
||||
int check_syncookie_clsact(struct __sk_buff *skb)
|
||||
{
|
||||
check_syncookie(skb, (void *)(long)skb->data,
|
||||
@@ -156,7 +156,7 @@ int check_syncookie_clsact(struct __sk_buff *skb)
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("xdp/check_syncookie")
|
||||
SEC("xdp")
|
||||
int check_syncookie_xdp(struct xdp_md *ctx)
|
||||
{
|
||||
check_syncookie(ctx, (void *)(long)ctx->data,
|
||||
|
||||
@@ -594,7 +594,7 @@ static int handle_parse_hdr(struct bpf_sock_ops *skops)
|
||||
return CG_OK;
|
||||
}
|
||||
|
||||
SEC("sockops/estab")
|
||||
SEC("sockops")
|
||||
int estab(struct bpf_sock_ops *skops)
|
||||
{
|
||||
int true_val = 1;
|
||||
|
||||
@@ -24,8 +24,8 @@ struct {
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(max_entries, 2);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(__u32));
|
||||
__type(key, int);
|
||||
__type(value, __u32);
|
||||
} perf_event_map SEC(".maps");
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
@@ -210,7 +210,7 @@ static __always_inline int handle_ipv6(struct xdp_md *xdp)
|
||||
return XDP_TX;
|
||||
}
|
||||
|
||||
SEC("xdp_tx_iptunnel")
|
||||
SEC("xdp")
|
||||
int _xdp_tx_iptunnel(struct xdp_md *xdp)
|
||||
{
|
||||
void *data_end = (void *)(long)xdp->data_end;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
SEC("xdp_adjust_tail_grow")
|
||||
SEC("xdp")
|
||||
int _xdp_adjust_tail_grow(struct xdp_md *xdp)
|
||||
{
|
||||
void *data_end = (void *)(long)xdp->data_end;
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
SEC("xdp_adjust_tail_shrink")
|
||||
SEC("xdp")
|
||||
int _xdp_adjust_tail_shrink(struct xdp_md *xdp)
|
||||
{
|
||||
void *data_end = (void *)(long)xdp->data_end;
|
||||
|
||||
@@ -36,8 +36,8 @@ struct meta {
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(int));
|
||||
__uint(value_size, sizeof(int));
|
||||
__type(key, int);
|
||||
__type(value, int);
|
||||
} perf_buf_map SEC(".maps");
|
||||
|
||||
__u64 test_result_fentry = 0;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
SEC("xdp_dm_log")
|
||||
SEC("xdp")
|
||||
int xdpdm_devlog(struct xdp_md *ctx)
|
||||
{
|
||||
char fmt[] = "devmap redirect: dev %u -> dev %u len %u\n";
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
|
||||
SEC("xdp/handler")
|
||||
SEC("xdp")
|
||||
int xdp_handler(struct xdp_md *xdp)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -206,7 +206,7 @@ static __always_inline int handle_ipv6(struct xdp_md *xdp)
|
||||
return XDP_TX;
|
||||
}
|
||||
|
||||
SEC("xdp_tx_iptunnel")
|
||||
SEC("xdp")
|
||||
int _xdp_tx_iptunnel(struct xdp_md *xdp)
|
||||
{
|
||||
void *data_end = (void *)(long)xdp->data_end;
|
||||
|
||||
@@ -797,7 +797,7 @@ out:
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
SEC("xdp-test-v4")
|
||||
SEC("xdp")
|
||||
int balancer_ingress_v4(struct xdp_md *ctx)
|
||||
{
|
||||
void *data = (void *)(long)ctx->data;
|
||||
@@ -816,7 +816,7 @@ int balancer_ingress_v4(struct xdp_md *ctx)
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
SEC("xdp-test-v6")
|
||||
SEC("xdp")
|
||||
int balancer_ingress_v6(struct xdp_md *ctx)
|
||||
{
|
||||
void *data = (void *)(long)ctx->data;
|
||||
|
||||
@@ -12,13 +12,13 @@ struct {
|
||||
__uint(max_entries, 4);
|
||||
} cpu_map SEC(".maps");
|
||||
|
||||
SEC("xdp_redir")
|
||||
SEC("xdp")
|
||||
int xdp_redir_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return bpf_redirect_map(&cpu_map, 1, 0);
|
||||
}
|
||||
|
||||
SEC("xdp_dummy")
|
||||
SEC("xdp")
|
||||
int xdp_dummy_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return XDP_PASS;
|
||||
|
||||
@@ -9,7 +9,7 @@ struct {
|
||||
__uint(max_entries, 4);
|
||||
} dm_ports SEC(".maps");
|
||||
|
||||
SEC("xdp_redir")
|
||||
SEC("xdp")
|
||||
int xdp_redir_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return bpf_redirect_map(&dm_ports, 1, 0);
|
||||
@@ -18,7 +18,7 @@ int xdp_redir_prog(struct xdp_md *ctx)
|
||||
/* invalid program on DEVMAP entry;
|
||||
* SEC name means expected attach type not set
|
||||
*/
|
||||
SEC("xdp_dummy")
|
||||
SEC("xdp")
|
||||
int xdp_dummy_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return XDP_PASS;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
int null_data_vprintk_ret = 0;
|
||||
int trace_vprintk_ret = 0;
|
||||
int trace_vprintk_ran = 0;
|
||||
|
||||
SEC("fentry/__x64_sys_nanosleep")
|
||||
int sys_enter(void *ctx)
|
||||
{
|
||||
static const char one[] = "1";
|
||||
static const char three[] = "3";
|
||||
static const char five[] = "5";
|
||||
static const char seven[] = "7";
|
||||
static const char nine[] = "9";
|
||||
static const char f[] = "%pS\n";
|
||||
|
||||
/* runner doesn't search for \t, just ensure it compiles */
|
||||
bpf_printk("\t");
|
||||
|
||||
trace_vprintk_ret = __bpf_vprintk("%s,%d,%s,%d,%s,%d,%s,%d,%s,%d %d\n",
|
||||
one, 2, three, 4, five, 6, seven, 8, nine, 10, ++trace_vprintk_ran);
|
||||
|
||||
/* non-NULL fmt w/ NULL data should result in error */
|
||||
null_data_vprintk_ret = bpf_trace_vprintk(f, sizeof(f), NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
SEC("xdp_dummy")
|
||||
SEC("xdp")
|
||||
int xdp_dummy_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return XDP_PASS;
|
||||
|
||||
@@ -34,7 +34,7 @@ struct {
|
||||
__uint(max_entries, 128);
|
||||
} mac_map SEC(".maps");
|
||||
|
||||
SEC("xdp_redirect_map_multi")
|
||||
SEC("xdp")
|
||||
int xdp_redirect_map_multi_prog(struct xdp_md *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
@@ -63,7 +63,7 @@ int xdp_redirect_map_multi_prog(struct xdp_md *ctx)
|
||||
}
|
||||
|
||||
/* The following 2 progs are for 2nd devmap prog testing */
|
||||
SEC("xdp_redirect_map_ingress")
|
||||
SEC("xdp")
|
||||
int xdp_redirect_map_all_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return bpf_redirect_map(&map_egress, 0,
|
||||
|
||||
@@ -86,7 +86,7 @@ static __always_inline int icmp_check(struct xdp_md *ctx, int type)
|
||||
return XDP_TX;
|
||||
}
|
||||
|
||||
SEC("xdpclient")
|
||||
SEC("xdp")
|
||||
int xdping_client(struct xdp_md *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
@@ -150,7 +150,7 @@ int xdping_client(struct xdp_md *ctx)
|
||||
return XDP_TX;
|
||||
}
|
||||
|
||||
SEC("xdpserver")
|
||||
SEC("xdp")
|
||||
int xdping_server(struct xdp_md *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/types.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
enum pkt_parse_err {
|
||||
NO_ERR,
|
||||
BAD_IP6_HDR,
|
||||
BAD_IP4GUE_HDR,
|
||||
BAD_IP6GUE_HDR,
|
||||
};
|
||||
|
||||
enum pkt_flag {
|
||||
TUNNEL = 0x1,
|
||||
TCP_SYN = 0x2,
|
||||
QUIC_INITIAL_FLAG = 0x4,
|
||||
TCP_ACK = 0x8,
|
||||
TCP_RST = 0x10
|
||||
};
|
||||
|
||||
struct v4_lpm_key {
|
||||
__u32 prefixlen;
|
||||
__u32 src;
|
||||
};
|
||||
|
||||
struct v4_lpm_val {
|
||||
struct v4_lpm_key key;
|
||||
__u8 val;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 16);
|
||||
__type(key, struct in6_addr);
|
||||
__type(value, bool);
|
||||
} v6_addr_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 16);
|
||||
__type(key, __u32);
|
||||
__type(value, bool);
|
||||
} v4_addr_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
|
||||
__uint(max_entries, 16);
|
||||
__uint(key_size, sizeof(struct v4_lpm_key));
|
||||
__uint(value_size, sizeof(struct v4_lpm_val));
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
} v4_lpm_val_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 16);
|
||||
__type(key, int);
|
||||
__type(value, __u8);
|
||||
} tcp_port_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 16);
|
||||
__type(key, int);
|
||||
__type(value, __u16);
|
||||
} udp_port_map SEC(".maps");
|
||||
|
||||
enum ip_type { V4 = 1, V6 = 2 };
|
||||
|
||||
struct fw_match_info {
|
||||
__u8 v4_src_ip_match;
|
||||
__u8 v6_src_ip_match;
|
||||
__u8 v4_src_prefix_match;
|
||||
__u8 v4_dst_prefix_match;
|
||||
__u8 tcp_dp_match;
|
||||
__u16 udp_sp_match;
|
||||
__u16 udp_dp_match;
|
||||
bool is_tcp;
|
||||
bool is_tcp_syn;
|
||||
};
|
||||
|
||||
struct pkt_info {
|
||||
enum ip_type type;
|
||||
union {
|
||||
struct iphdr *ipv4;
|
||||
struct ipv6hdr *ipv6;
|
||||
} ip;
|
||||
int sport;
|
||||
int dport;
|
||||
__u16 trans_hdr_offset;
|
||||
__u8 proto;
|
||||
__u8 flags;
|
||||
};
|
||||
|
||||
static __always_inline struct ethhdr *parse_ethhdr(void *data, void *data_end)
|
||||
{
|
||||
struct ethhdr *eth = data;
|
||||
|
||||
if (eth + 1 > data_end)
|
||||
return NULL;
|
||||
|
||||
return eth;
|
||||
}
|
||||
|
||||
static __always_inline __u8 filter_ipv6_addr(const struct in6_addr *ipv6addr)
|
||||
{
|
||||
__u8 *leaf;
|
||||
|
||||
leaf = bpf_map_lookup_elem(&v6_addr_map, ipv6addr);
|
||||
|
||||
return leaf ? *leaf : 0;
|
||||
}
|
||||
|
||||
static __always_inline __u8 filter_ipv4_addr(const __u32 ipaddr)
|
||||
{
|
||||
__u8 *leaf;
|
||||
|
||||
leaf = bpf_map_lookup_elem(&v4_addr_map, &ipaddr);
|
||||
|
||||
return leaf ? *leaf : 0;
|
||||
}
|
||||
|
||||
static __always_inline __u8 filter_ipv4_lpm(const __u32 ipaddr)
|
||||
{
|
||||
struct v4_lpm_key v4_key = {};
|
||||
struct v4_lpm_val *lpm_val;
|
||||
|
||||
v4_key.src = ipaddr;
|
||||
v4_key.prefixlen = 32;
|
||||
|
||||
lpm_val = bpf_map_lookup_elem(&v4_lpm_val_map, &v4_key);
|
||||
|
||||
return lpm_val ? lpm_val->val : 0;
|
||||
}
|
||||
|
||||
|
||||
static __always_inline void
|
||||
filter_src_dst_ip(struct pkt_info* info, struct fw_match_info* match_info)
|
||||
{
|
||||
if (info->type == V6) {
|
||||
match_info->v6_src_ip_match =
|
||||
filter_ipv6_addr(&info->ip.ipv6->saddr);
|
||||
} else if (info->type == V4) {
|
||||
match_info->v4_src_ip_match =
|
||||
filter_ipv4_addr(info->ip.ipv4->saddr);
|
||||
match_info->v4_src_prefix_match =
|
||||
filter_ipv4_lpm(info->ip.ipv4->saddr);
|
||||
match_info->v4_dst_prefix_match =
|
||||
filter_ipv4_lpm(info->ip.ipv4->daddr);
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void *
|
||||
get_transport_hdr(__u16 offset, void *data, void *data_end)
|
||||
{
|
||||
if (offset > 255 || data + offset > data_end)
|
||||
return NULL;
|
||||
|
||||
return data + offset;
|
||||
}
|
||||
|
||||
static __always_inline bool tcphdr_only_contains_flag(struct tcphdr *tcp,
|
||||
__u32 FLAG)
|
||||
{
|
||||
return (tcp_flag_word(tcp) &
|
||||
(TCP_FLAG_ACK | TCP_FLAG_RST | TCP_FLAG_SYN | TCP_FLAG_FIN)) == FLAG;
|
||||
}
|
||||
|
||||
static __always_inline void set_tcp_flags(struct pkt_info *info,
|
||||
struct tcphdr *tcp) {
|
||||
if (tcphdr_only_contains_flag(tcp, TCP_FLAG_SYN))
|
||||
info->flags |= TCP_SYN;
|
||||
else if (tcphdr_only_contains_flag(tcp, TCP_FLAG_ACK))
|
||||
info->flags |= TCP_ACK;
|
||||
else if (tcphdr_only_contains_flag(tcp, TCP_FLAG_RST))
|
||||
info->flags |= TCP_RST;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
parse_tcp(struct pkt_info *info, void *transport_hdr, void *data_end)
|
||||
{
|
||||
struct tcphdr *tcp = transport_hdr;
|
||||
|
||||
if (tcp + 1 > data_end)
|
||||
return false;
|
||||
|
||||
info->sport = bpf_ntohs(tcp->source);
|
||||
info->dport = bpf_ntohs(tcp->dest);
|
||||
set_tcp_flags(info, tcp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
parse_udp(struct pkt_info *info, void *transport_hdr, void *data_end)
|
||||
{
|
||||
struct udphdr *udp = transport_hdr;
|
||||
|
||||
if (udp + 1 > data_end)
|
||||
return false;
|
||||
|
||||
info->sport = bpf_ntohs(udp->source);
|
||||
info->dport = bpf_ntohs(udp->dest);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static __always_inline __u8 filter_tcp_port(int port)
|
||||
{
|
||||
__u8 *leaf = bpf_map_lookup_elem(&tcp_port_map, &port);
|
||||
|
||||
return leaf ? *leaf : 0;
|
||||
}
|
||||
|
||||
static __always_inline __u16 filter_udp_port(int port)
|
||||
{
|
||||
__u16 *leaf = bpf_map_lookup_elem(&udp_port_map, &port);
|
||||
|
||||
return leaf ? *leaf : 0;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
filter_transport_hdr(void *transport_hdr, void *data_end,
|
||||
struct pkt_info *info, struct fw_match_info *match_info)
|
||||
{
|
||||
if (info->proto == IPPROTO_TCP) {
|
||||
if (!parse_tcp(info, transport_hdr, data_end))
|
||||
return false;
|
||||
|
||||
match_info->is_tcp = true;
|
||||
match_info->is_tcp_syn = (info->flags & TCP_SYN) > 0;
|
||||
|
||||
match_info->tcp_dp_match = filter_tcp_port(info->dport);
|
||||
} else if (info->proto == IPPROTO_UDP) {
|
||||
if (!parse_udp(info, transport_hdr, data_end))
|
||||
return false;
|
||||
|
||||
match_info->udp_dp_match = filter_udp_port(info->dport);
|
||||
match_info->udp_sp_match = filter_udp_port(info->sport);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static __always_inline __u8
|
||||
parse_gue_v6(struct pkt_info *info, struct ipv6hdr *ip6h, void *data_end)
|
||||
{
|
||||
struct udphdr *udp = (struct udphdr *)(ip6h + 1);
|
||||
void *encap_data = udp + 1;
|
||||
|
||||
if (udp + 1 > data_end)
|
||||
return BAD_IP6_HDR;
|
||||
|
||||
if (udp->dest != bpf_htons(6666))
|
||||
return NO_ERR;
|
||||
|
||||
info->flags |= TUNNEL;
|
||||
|
||||
if (encap_data + 1 > data_end)
|
||||
return BAD_IP6GUE_HDR;
|
||||
|
||||
if (*(__u8 *)encap_data & 0x30) {
|
||||
struct ipv6hdr *inner_ip6h = encap_data;
|
||||
|
||||
if (inner_ip6h + 1 > data_end)
|
||||
return BAD_IP6GUE_HDR;
|
||||
|
||||
info->type = V6;
|
||||
info->proto = inner_ip6h->nexthdr;
|
||||
info->ip.ipv6 = inner_ip6h;
|
||||
info->trans_hdr_offset += sizeof(struct ipv6hdr) + sizeof(struct udphdr);
|
||||
} else {
|
||||
struct iphdr *inner_ip4h = encap_data;
|
||||
|
||||
if (inner_ip4h + 1 > data_end)
|
||||
return BAD_IP6GUE_HDR;
|
||||
|
||||
info->type = V4;
|
||||
info->proto = inner_ip4h->protocol;
|
||||
info->ip.ipv4 = inner_ip4h;
|
||||
info->trans_hdr_offset += sizeof(struct iphdr) + sizeof(struct udphdr);
|
||||
}
|
||||
|
||||
return NO_ERR;
|
||||
}
|
||||
|
||||
static __always_inline __u8 parse_ipv6_gue(struct pkt_info *info,
|
||||
void *data, void *data_end)
|
||||
{
|
||||
struct ipv6hdr *ip6h = data + sizeof(struct ethhdr);
|
||||
|
||||
if (ip6h + 1 > data_end)
|
||||
return BAD_IP6_HDR;
|
||||
|
||||
info->proto = ip6h->nexthdr;
|
||||
info->ip.ipv6 = ip6h;
|
||||
info->type = V6;
|
||||
info->trans_hdr_offset = sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
|
||||
|
||||
if (info->proto == IPPROTO_UDP)
|
||||
return parse_gue_v6(info, ip6h, data_end);
|
||||
|
||||
return NO_ERR;
|
||||
}
|
||||
|
||||
SEC("xdp")
|
||||
int edgewall(struct xdp_md *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)(ctx->data_end);
|
||||
void *data = (void *)(long)(ctx->data);
|
||||
struct fw_match_info match_info = {};
|
||||
struct pkt_info info = {};
|
||||
__u8 parse_err = NO_ERR;
|
||||
void *transport_hdr;
|
||||
struct ethhdr *eth;
|
||||
bool filter_res;
|
||||
__u32 proto;
|
||||
|
||||
eth = parse_ethhdr(data, data_end);
|
||||
if (!eth)
|
||||
return XDP_DROP;
|
||||
|
||||
proto = eth->h_proto;
|
||||
if (proto != bpf_htons(ETH_P_IPV6))
|
||||
return XDP_DROP;
|
||||
|
||||
if (parse_ipv6_gue(&info, data, data_end))
|
||||
return XDP_DROP;
|
||||
|
||||
if (info.proto == IPPROTO_ICMPV6)
|
||||
return XDP_PASS;
|
||||
|
||||
if (info.proto != IPPROTO_TCP && info.proto != IPPROTO_UDP)
|
||||
return XDP_DROP;
|
||||
|
||||
filter_src_dst_ip(&info, &match_info);
|
||||
|
||||
transport_hdr = get_transport_hdr(info.trans_hdr_offset, data,
|
||||
data_end);
|
||||
if (!transport_hdr)
|
||||
return XDP_DROP;
|
||||
|
||||
filter_res = filter_transport_hdr(transport_hdr, data_end,
|
||||
&info, &match_info);
|
||||
if (!filter_res)
|
||||
return XDP_DROP;
|
||||
|
||||
if (match_info.is_tcp && !match_info.is_tcp_syn)
|
||||
return XDP_PASS;
|
||||
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
@@ -57,6 +57,11 @@ def default_iface(f):
|
||||
return f(*args, iface, **kwargs)
|
||||
return wrapper
|
||||
|
||||
DMESG_EMITTING_HELPERS = [
|
||||
"bpf_probe_write_user",
|
||||
"bpf_trace_printk",
|
||||
"bpf_trace_vprintk",
|
||||
]
|
||||
|
||||
class TestBpftool(unittest.TestCase):
|
||||
@classmethod
|
||||
@@ -67,10 +72,7 @@ class TestBpftool(unittest.TestCase):
|
||||
|
||||
@default_iface
|
||||
def test_feature_dev_json(self, iface):
|
||||
unexpected_helpers = [
|
||||
"bpf_probe_write_user",
|
||||
"bpf_trace_printk",
|
||||
]
|
||||
unexpected_helpers = DMESG_EMITTING_HELPERS
|
||||
expected_keys = [
|
||||
"syscall_config",
|
||||
"program_types",
|
||||
@@ -94,10 +96,7 @@ class TestBpftool(unittest.TestCase):
|
||||
bpftool_json(["feature", "probe"]),
|
||||
bpftool_json(["feature"]),
|
||||
]
|
||||
unexpected_helpers = [
|
||||
"bpf_probe_write_user",
|
||||
"bpf_trace_printk",
|
||||
]
|
||||
unexpected_helpers = DMESG_EMITTING_HELPERS
|
||||
expected_keys = [
|
||||
"syscall_config",
|
||||
"system_config",
|
||||
@@ -121,10 +120,7 @@ class TestBpftool(unittest.TestCase):
|
||||
bpftool_json(["feature", "probe", "kernel", "full"]),
|
||||
bpftool_json(["feature", "probe", "full"]),
|
||||
]
|
||||
expected_helpers = [
|
||||
"bpf_probe_write_user",
|
||||
"bpf_trace_printk",
|
||||
]
|
||||
expected_helpers = DMESG_EMITTING_HELPERS
|
||||
|
||||
for tc in test_cases:
|
||||
# Check if expected helpers are included at least once in any
|
||||
@@ -157,7 +153,7 @@ class TestBpftool(unittest.TestCase):
|
||||
not_full_set.add(helper)
|
||||
|
||||
self.assertCountEqual(full_set - not_full_set,
|
||||
{"bpf_probe_write_user", "bpf_trace_printk"})
|
||||
set(DMESG_EMITTING_HELPERS))
|
||||
self.assertCountEqual(not_full_set - full_set, set())
|
||||
|
||||
def test_feature_macros(self):
|
||||
|
||||
@@ -76,8 +76,8 @@ DIR=$(dirname $0)
|
||||
TEST_IF=lo
|
||||
MAX_PING_TRIES=5
|
||||
BPF_PROG_OBJ="${DIR}/test_tcp_check_syncookie_kern.o"
|
||||
CLSACT_SECTION="clsact/check_syncookie"
|
||||
XDP_SECTION="xdp/check_syncookie"
|
||||
CLSACT_SECTION="tc"
|
||||
XDP_SECTION="xdp"
|
||||
BPF_PROG_ID=0
|
||||
PROG="${DIR}/test_tcp_check_syncookie_user"
|
||||
|
||||
|
||||
@@ -168,14 +168,15 @@ add_vxlan_tunnel()
|
||||
ip netns exec at_ns0 \
|
||||
ip link set dev $DEV_NS address 52:54:00:d9:01:00 up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 arp -s 10.1.1.200 52:54:00:d9:02:00
|
||||
ip netns exec at_ns0 \
|
||||
ip neigh add 10.1.1.200 lladdr 52:54:00:d9:02:00 dev $DEV_NS
|
||||
ip netns exec at_ns0 iptables -A OUTPUT -j MARK --set-mark 0x800FF
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external gbp dstport 4789
|
||||
ip link set dev $DEV address 52:54:00:d9:02:00 up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
arp -s 10.1.1.100 52:54:00:d9:01:00
|
||||
ip neigh add 10.1.1.100 lladdr 52:54:00:d9:01:00 dev $DEV
|
||||
}
|
||||
|
||||
add_ip6vxlan_tunnel()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
readonly KSFT_SKIP=4
|
||||
|
||||
cleanup()
|
||||
{
|
||||
if [ "$?" = "0" ]; then
|
||||
@@ -17,7 +20,7 @@ cleanup()
|
||||
ip link set dev lo xdp off 2>/dev/null > /dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "selftests: [SKIP] Could not run test without the ip xdp support"
|
||||
exit 0
|
||||
exit $KSFT_SKIP
|
||||
fi
|
||||
set -e
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ test_xdp_redirect()
|
||||
return 0
|
||||
fi
|
||||
|
||||
ip -n ns1 link set veth11 $xdpmode obj xdp_dummy.o sec xdp_dummy &> /dev/null
|
||||
ip -n ns2 link set veth22 $xdpmode obj xdp_dummy.o sec xdp_dummy &> /dev/null
|
||||
ip -n ns1 link set veth11 $xdpmode obj xdp_dummy.o sec xdp &> /dev/null
|
||||
ip -n ns2 link set veth22 $xdpmode obj xdp_dummy.o sec xdp &> /dev/null
|
||||
ip link set dev veth1 $xdpmode obj test_xdp_redirect.o sec redirect_to_222 &> /dev/null
|
||||
ip link set dev veth2 $xdpmode obj test_xdp_redirect.o sec redirect_to_111 &> /dev/null
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ setup_ns()
|
||||
# Add a neigh entry for IPv4 ping test
|
||||
ip -n ns$i neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0
|
||||
ip -n ns$i link set veth0 $mode obj \
|
||||
xdp_dummy.o sec xdp_dummy &> /dev/null || \
|
||||
xdp_dummy.o sec xdp &> /dev/null || \
|
||||
{ test_fail "Unable to load dummy xdp" && exit 1; }
|
||||
IFACES="$IFACES veth$i"
|
||||
veth_mac[$i]=$(ip link show veth$i | awk '/link\/ether/ {print $2}')
|
||||
|
||||
@@ -107,9 +107,9 @@ ip link set dev veth1 xdp pinned $BPF_DIR/progs/redirect_map_0
|
||||
ip link set dev veth2 xdp pinned $BPF_DIR/progs/redirect_map_1
|
||||
ip link set dev veth3 xdp pinned $BPF_DIR/progs/redirect_map_2
|
||||
|
||||
ip -n ns1 link set dev veth11 xdp obj xdp_dummy.o sec xdp_dummy
|
||||
ip -n ns1 link set dev veth11 xdp obj xdp_dummy.o sec xdp
|
||||
ip -n ns2 link set dev veth22 xdp obj xdp_tx.o sec xdp
|
||||
ip -n ns3 link set dev veth33 xdp obj xdp_dummy.o sec xdp_dummy
|
||||
ip -n ns3 link set dev veth33 xdp obj xdp_dummy.o sec xdp
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Author: Jesper Dangaard Brouer <hawk@kernel.org>
|
||||
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
readonly KSFT_SKIP=4
|
||||
|
||||
# Allow wrapper scripts to name test
|
||||
if [ -z "$TESTNAME" ]; then
|
||||
TESTNAME=xdp_vlan
|
||||
@@ -94,7 +97,7 @@ while true; do
|
||||
-h | --help )
|
||||
usage;
|
||||
echo "selftests: $TESTNAME [SKIP] usage help info requested"
|
||||
exit 0
|
||||
exit $KSFT_SKIP
|
||||
;;
|
||||
* )
|
||||
shift
|
||||
@@ -117,7 +120,7 @@ fi
|
||||
ip link set dev lo xdpgeneric off 2>/dev/null > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "selftests: $TESTNAME [SKIP] need ip xdp support"
|
||||
exit 0
|
||||
exit $KSFT_SKIP
|
||||
fi
|
||||
|
||||
# Interactive mode likely require us to cleanup netns
|
||||
|
||||
@@ -104,3 +104,164 @@
|
||||
.result = ACCEPT,
|
||||
.retval = POINTER_VALUE,
|
||||
},
|
||||
{
|
||||
"Spill and refill a u32 const scalar. Offset to skb->data",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data_end)),
|
||||
/* r4 = 20 */
|
||||
BPF_MOV32_IMM(BPF_REG_4, 20),
|
||||
/* *(u32 *)(r10 -8) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* r4 = *(u32 *)(r10 -8) */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_10, -8),
|
||||
/* r0 = r2 */
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
/* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=inv20 */
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
|
||||
/* if (r0 > r3) R0=pkt,off=20 R2=pkt R3=pkt_end R4=inv20 */
|
||||
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
|
||||
/* r0 = *(u32 *)r2 R0=pkt,off=20,r=20 R2=pkt,r=20 R3=pkt_end R4=inv20 */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"Spill a u32 const, refill from another half of the uninit u32 from the stack",
|
||||
.insns = {
|
||||
/* r4 = 20 */
|
||||
BPF_MOV32_IMM(BPF_REG_4, 20),
|
||||
/* *(u32 *)(r10 -8) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* r4 = *(u32 *)(r10 -4) fp-8=????rrrr*/
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_10, -4),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = REJECT,
|
||||
.errstr = "invalid read from stack off -4+0 size 4",
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"Spill a u32 const scalar. Refill as u16. Offset to skb->data",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data_end)),
|
||||
/* r4 = 20 */
|
||||
BPF_MOV32_IMM(BPF_REG_4, 20),
|
||||
/* *(u32 *)(r10 -8) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* r4 = *(u16 *)(r10 -8) */
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_10, -8),
|
||||
/* r0 = r2 */
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
/* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=inv,umax=65535 */
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
|
||||
/* if (r0 > r3) R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv,umax=65535 */
|
||||
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
|
||||
/* r0 = *(u32 *)r2 R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv20 */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to packet",
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"Spill a u32 const scalar. Refill as u16 from fp-6. Offset to skb->data",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data_end)),
|
||||
/* r4 = 20 */
|
||||
BPF_MOV32_IMM(BPF_REG_4, 20),
|
||||
/* *(u32 *)(r10 -8) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* r4 = *(u16 *)(r10 -6) */
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_10, -6),
|
||||
/* r0 = r2 */
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
/* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=inv,umax=65535 */
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
|
||||
/* if (r0 > r3) R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv,umax=65535 */
|
||||
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
|
||||
/* r0 = *(u32 *)r2 R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv20 */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to packet",
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"Spill and refill a u32 const scalar at non 8byte aligned stack addr. Offset to skb->data",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data_end)),
|
||||
/* r4 = 20 */
|
||||
BPF_MOV32_IMM(BPF_REG_4, 20),
|
||||
/* *(u32 *)(r10 -8) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* *(u32 *)(r10 -4) = r4 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -4),
|
||||
/* r4 = *(u32 *)(r10 -4), */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_10, -4),
|
||||
/* r0 = r2 */
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
/* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=inv,umax=U32_MAX */
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
|
||||
/* if (r0 > r3) R0=pkt,umax=U32_MAX R2=pkt R3=pkt_end R4=inv */
|
||||
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
|
||||
/* r0 = *(u32 *)r2 R0=pkt,umax=U32_MAX R2=pkt R3=pkt_end R4=inv */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to packet",
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"Spill and refill a umax=40 bounded scalar. Offset to skb->data",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data_end)),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, tstamp)),
|
||||
BPF_JMP_IMM(BPF_JLE, BPF_REG_4, 40, 2),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
/* *(u32 *)(r10 -8) = r4 R4=inv,umax=40 */
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_4, -8),
|
||||
/* r4 = (*u32 *)(r10 - 8) */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_10, -8),
|
||||
/* r2 += r4 R2=pkt R4=inv,umax=40 */
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_4),
|
||||
/* r0 = r2 R2=pkt,umax=40 R4=inv,umax=40 */
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
/* r2 += 20 R0=pkt,umax=40 R2=pkt,umax=40 */
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 20),
|
||||
/* if (r2 > r3) R0=pkt,umax=40 R2=pkt,off=20,umax=40 */
|
||||
BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_3, 1),
|
||||
/* r0 = *(u32 *)r0 R0=pkt,r=20,umax=40 R2=pkt,off=20,r=20,umax=40 */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
|
||||
@@ -178,9 +178,8 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
main_prog = bpf_object__find_program_by_title(obj,
|
||||
server ? "xdpserver" :
|
||||
"xdpclient");
|
||||
main_prog = bpf_object__find_program_by_name(obj,
|
||||
server ? "xdping_server" : "xdping_client");
|
||||
if (main_prog)
|
||||
prog_fd = bpf_program__fd(main_prog);
|
||||
if (!main_prog || prog_fd < 0) {
|
||||
|
||||
@@ -384,6 +384,7 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
|
||||
ifobj->umem = &ifobj->umem_arr[0];
|
||||
ifobj->xsk = &ifobj->xsk_arr[0];
|
||||
ifobj->use_poll = false;
|
||||
ifobj->pacing_on = true;
|
||||
ifobj->pkt_stream = test->pkt_stream_default;
|
||||
|
||||
if (i == 0) {
|
||||
@@ -445,6 +446,12 @@ static void test_spec_set_name(struct test_spec *test, const char *name)
|
||||
strncpy(test->name, name, MAX_TEST_NAME_SIZE);
|
||||
}
|
||||
|
||||
static void pkt_stream_reset(struct pkt_stream *pkt_stream)
|
||||
{
|
||||
if (pkt_stream)
|
||||
pkt_stream->rx_pkt_nb = 0;
|
||||
}
|
||||
|
||||
static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
|
||||
{
|
||||
if (pkt_nb >= pkt_stream->nb_pkts)
|
||||
@@ -507,8 +514,7 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb
|
||||
|
||||
pkt_stream->nb_pkts = nb_pkts;
|
||||
for (i = 0; i < nb_pkts; i++) {
|
||||
pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size +
|
||||
DEFAULT_OFFSET;
|
||||
pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
|
||||
pkt_stream->pkts[i].len = pkt_len;
|
||||
pkt_stream->pkts[i].payload = i;
|
||||
|
||||
@@ -536,14 +542,14 @@ static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len)
|
||||
test->ifobj_rx->pkt_stream = pkt_stream;
|
||||
}
|
||||
|
||||
static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, u32 offset)
|
||||
static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset)
|
||||
{
|
||||
struct xsk_umem_info *umem = test->ifobj_tx->umem;
|
||||
struct pkt_stream *pkt_stream;
|
||||
u32 i;
|
||||
|
||||
pkt_stream = pkt_stream_clone(umem, test->pkt_stream_default);
|
||||
for (i = 0; i < test->pkt_stream_default->nb_pkts; i += 2) {
|
||||
for (i = 1; i < test->pkt_stream_default->nb_pkts; i += 2) {
|
||||
pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size + offset;
|
||||
pkt_stream->pkts[i].len = pkt_len;
|
||||
}
|
||||
@@ -635,6 +641,25 @@ static void pkt_dump(void *pkt, u32 len)
|
||||
fprintf(stdout, "---------------------------------------\n");
|
||||
}
|
||||
|
||||
static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr,
|
||||
u64 pkt_stream_addr)
|
||||
{
|
||||
u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom;
|
||||
u32 offset = addr % umem->frame_size, expected_offset = 0;
|
||||
|
||||
if (!pkt_stream->use_addr_for_fill)
|
||||
pkt_stream_addr = 0;
|
||||
|
||||
expected_offset += (pkt_stream_addr + headroom + XDP_PACKET_HEADROOM) % umem->frame_size;
|
||||
|
||||
if (offset == expected_offset)
|
||||
return true;
|
||||
|
||||
ksft_test_result_fail("ERROR: [%s] expected [%u], got [%u]\n", __func__, expected_offset,
|
||||
offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len)
|
||||
{
|
||||
void *data = xsk_umem__get_data(buffer, addr);
|
||||
@@ -717,13 +742,15 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *
|
||||
struct pollfd *fds)
|
||||
{
|
||||
struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
|
||||
struct xsk_umem_info *umem = xsk->umem;
|
||||
u32 idx_rx = 0, idx_fq = 0, rcvd, i;
|
||||
u32 total = 0;
|
||||
int ret;
|
||||
|
||||
while (pkt) {
|
||||
rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
|
||||
if (!rcvd) {
|
||||
if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
|
||||
if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
|
||||
ret = poll(fds, 1, POLL_TMOUT);
|
||||
if (ret < 0)
|
||||
exit_with_error(-ret);
|
||||
@@ -731,16 +758,16 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
|
||||
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
|
||||
while (ret != rcvd) {
|
||||
if (ret < 0)
|
||||
exit_with_error(-ret);
|
||||
if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
|
||||
if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
|
||||
ret = poll(fds, 1, POLL_TMOUT);
|
||||
if (ret < 0)
|
||||
exit_with_error(-ret);
|
||||
}
|
||||
ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
|
||||
ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
|
||||
}
|
||||
|
||||
for (i = 0; i < rcvd; i++) {
|
||||
@@ -757,15 +784,25 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *
|
||||
|
||||
orig = xsk_umem__extract_addr(addr);
|
||||
addr = xsk_umem__add_offset_to_addr(addr);
|
||||
if (!is_pkt_valid(pkt, xsk->umem->buffer, addr, desc->len))
|
||||
|
||||
if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len))
|
||||
return;
|
||||
if (!is_offset_correct(umem, pkt_stream, addr, pkt->addr))
|
||||
return;
|
||||
|
||||
*xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
|
||||
*xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig;
|
||||
pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
|
||||
}
|
||||
|
||||
xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
|
||||
xsk_ring_prod__submit(&umem->fq, rcvd);
|
||||
xsk_ring_cons__release(&xsk->rx, rcvd);
|
||||
|
||||
pthread_mutex_lock(&pacing_mutex);
|
||||
pkts_in_flight -= rcvd;
|
||||
total += rcvd;
|
||||
if (pkts_in_flight < umem->num_frames)
|
||||
pthread_cond_signal(&pacing_cond);
|
||||
pthread_mutex_unlock(&pacing_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,10 +828,19 @@ static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb)
|
||||
valid_pkts++;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&pacing_mutex);
|
||||
pkts_in_flight += valid_pkts;
|
||||
if (ifobject->pacing_on && pkts_in_flight >= ifobject->umem->num_frames - BATCH_SIZE) {
|
||||
kick_tx(xsk);
|
||||
pthread_cond_wait(&pacing_cond, &pacing_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&pacing_mutex);
|
||||
|
||||
xsk_ring_prod__submit(&xsk->tx, i);
|
||||
xsk->outstanding_tx += valid_pkts;
|
||||
complete_pkts(xsk, BATCH_SIZE);
|
||||
complete_pkts(xsk, i);
|
||||
|
||||
usleep(10);
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -813,8 +859,6 @@ static void send_pkts(struct ifobject *ifobject)
|
||||
fds.events = POLLOUT;
|
||||
|
||||
while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
|
||||
u32 sent;
|
||||
|
||||
if (ifobject->use_poll) {
|
||||
int ret;
|
||||
|
||||
@@ -826,9 +870,7 @@ static void send_pkts(struct ifobject *ifobject)
|
||||
continue;
|
||||
}
|
||||
|
||||
sent = __send_pkts(ifobject, pkt_cnt);
|
||||
pkt_cnt += sent;
|
||||
usleep(10);
|
||||
pkt_cnt += __send_pkts(ifobject, pkt_cnt);
|
||||
}
|
||||
|
||||
wait_for_tx_completion(ifobject->xsk);
|
||||
@@ -913,18 +955,17 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
|
||||
u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
|
||||
u32 ctr = 0;
|
||||
void *bufs;
|
||||
int ret;
|
||||
|
||||
bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
|
||||
if (bufs == MAP_FAILED)
|
||||
exit_with_error(errno);
|
||||
|
||||
ret = xsk_configure_umem(&ifobject->umem_arr[i], bufs, umem_sz);
|
||||
if (ret)
|
||||
exit_with_error(-ret);
|
||||
|
||||
while (ctr++ < SOCK_RECONF_CTR) {
|
||||
int ret;
|
||||
|
||||
ret = xsk_configure_umem(&ifobject->umem_arr[i], bufs, umem_sz);
|
||||
if (ret)
|
||||
exit_with_error(-ret);
|
||||
|
||||
ret = xsk_configure_socket(&ifobject->xsk_arr[i], &ifobject->umem_arr[i],
|
||||
ifobject, i);
|
||||
if (!ret)
|
||||
@@ -971,13 +1012,18 @@ static void *worker_testapp_validate_tx(void *arg)
|
||||
|
||||
static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
|
||||
{
|
||||
u32 idx = 0, i;
|
||||
u32 idx = 0, i, buffers_to_fill;
|
||||
int ret;
|
||||
|
||||
ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
|
||||
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
|
||||
if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS)
|
||||
buffers_to_fill = umem->num_frames;
|
||||
else
|
||||
buffers_to_fill = XSK_RING_PROD__DEFAULT_NUM_DESCS;
|
||||
|
||||
ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx);
|
||||
if (ret != buffers_to_fill)
|
||||
exit_with_error(ENOSPC);
|
||||
for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++) {
|
||||
for (i = 0; i < buffers_to_fill; i++) {
|
||||
u64 addr;
|
||||
|
||||
if (pkt_stream->use_addr_for_fill) {
|
||||
@@ -987,12 +1033,12 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream
|
||||
break;
|
||||
addr = pkt->addr;
|
||||
} else {
|
||||
addr = (i % umem->num_frames) * umem->frame_size + DEFAULT_OFFSET;
|
||||
addr = i * umem->frame_size;
|
||||
}
|
||||
|
||||
*xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
|
||||
}
|
||||
xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
|
||||
xsk_ring_prod__submit(&umem->fq, buffers_to_fill);
|
||||
}
|
||||
|
||||
static void *worker_testapp_validate_rx(void *arg)
|
||||
@@ -1032,6 +1078,8 @@ static void testapp_validate_traffic(struct test_spec *test)
|
||||
exit_with_error(errno);
|
||||
|
||||
test->current_step++;
|
||||
pkt_stream_reset(ifobj_rx->pkt_stream);
|
||||
pkts_in_flight = 0;
|
||||
|
||||
/*Spawn RX thread */
|
||||
pthread_create(&t0, NULL, ifobj_rx->func_ptr, test);
|
||||
@@ -1108,6 +1156,13 @@ static void testapp_bpf_res(struct test_spec *test)
|
||||
testapp_validate_traffic(test);
|
||||
}
|
||||
|
||||
static void testapp_headroom(struct test_spec *test)
|
||||
{
|
||||
test_spec_set_name(test, "UMEM_HEADROOM");
|
||||
test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE;
|
||||
testapp_validate_traffic(test);
|
||||
}
|
||||
|
||||
static void testapp_stats(struct test_spec *test)
|
||||
{
|
||||
int i;
|
||||
@@ -1115,6 +1170,8 @@ static void testapp_stats(struct test_spec *test)
|
||||
for (i = 0; i < STAT_TEST_TYPE_MAX; i++) {
|
||||
test_spec_reset(test);
|
||||
stat_test_type = i;
|
||||
/* No or few packets will be received so cannot pace packets */
|
||||
test->ifobj_tx->pacing_on = false;
|
||||
|
||||
switch (stat_test_type) {
|
||||
case STAT_TEST_RX_DROPPED:
|
||||
@@ -1181,7 +1238,7 @@ static bool testapp_unaligned(struct test_spec *test)
|
||||
test->ifobj_tx->umem->unaligned_mode = true;
|
||||
test->ifobj_rx->umem->unaligned_mode = true;
|
||||
/* Let half of the packets straddle a buffer boundrary */
|
||||
pkt_stream_replace_half(test, PKT_SIZE, test->ifobj_tx->umem->frame_size - 32);
|
||||
pkt_stream_replace_half(test, PKT_SIZE, -PKT_SIZE / 2);
|
||||
test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
|
||||
testapp_validate_traffic(test);
|
||||
|
||||
@@ -1189,6 +1246,15 @@ static bool testapp_unaligned(struct test_spec *test)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void testapp_single_pkt(struct test_spec *test)
|
||||
{
|
||||
struct pkt pkts[] = {{0x1000, PKT_SIZE, 0, true}};
|
||||
|
||||
pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
|
||||
testapp_validate_traffic(test);
|
||||
pkt_stream_restore_default(test);
|
||||
}
|
||||
|
||||
static void testapp_invalid_desc(struct test_spec *test)
|
||||
{
|
||||
struct pkt pkts[] = {
|
||||
@@ -1270,6 +1336,10 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_
|
||||
test_spec_set_name(test, "RUN_TO_COMPLETION");
|
||||
testapp_validate_traffic(test);
|
||||
break;
|
||||
case TEST_TYPE_RUN_TO_COMPLETION_SINGLE_PKT:
|
||||
test_spec_set_name(test, "RUN_TO_COMPLETION_SINGLE_PKT");
|
||||
testapp_single_pkt(test);
|
||||
break;
|
||||
case TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME:
|
||||
test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE");
|
||||
test->ifobj_tx->umem->frame_size = 2048;
|
||||
@@ -1305,6 +1375,9 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_
|
||||
if (!testapp_unaligned(test))
|
||||
return;
|
||||
break;
|
||||
case TEST_TYPE_HEADROOM:
|
||||
testapp_headroom(test);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr))
|
||||
#define USLEEP_MAX 10000
|
||||
#define SOCK_RECONF_CTR 10
|
||||
#define BATCH_SIZE 8
|
||||
#define BATCH_SIZE 64
|
||||
#define POLL_TMOUT 1000
|
||||
#define DEFAULT_PKT_CNT (4 * 1024)
|
||||
#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4)
|
||||
#define UMEM_SIZE (DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE)
|
||||
#define RX_FULL_RXQSIZE 32
|
||||
#define DEFAULT_OFFSET 256
|
||||
#define UMEM_HEADROOM_TEST_SIZE 128
|
||||
#define XSK_UMEM__INVALID_FRAME_SIZE (XSK_UMEM__DEFAULT_FRAME_SIZE + 1)
|
||||
|
||||
#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0)
|
||||
@@ -55,11 +55,13 @@ enum test_mode {
|
||||
enum test_type {
|
||||
TEST_TYPE_RUN_TO_COMPLETION,
|
||||
TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME,
|
||||
TEST_TYPE_RUN_TO_COMPLETION_SINGLE_PKT,
|
||||
TEST_TYPE_POLL,
|
||||
TEST_TYPE_UNALIGNED,
|
||||
TEST_TYPE_ALIGNED_INV_DESC,
|
||||
TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME,
|
||||
TEST_TYPE_UNALIGNED_INV_DESC,
|
||||
TEST_TYPE_HEADROOM,
|
||||
TEST_TYPE_TEARDOWN,
|
||||
TEST_TYPE_BIDI,
|
||||
TEST_TYPE_STATS,
|
||||
@@ -136,6 +138,7 @@ struct ifobject {
|
||||
bool tx_on;
|
||||
bool rx_on;
|
||||
bool use_poll;
|
||||
bool pacing_on;
|
||||
u8 dst_mac[ETH_ALEN];
|
||||
u8 src_mac[ETH_ALEN];
|
||||
};
|
||||
@@ -151,5 +154,9 @@ struct test_spec {
|
||||
};
|
||||
|
||||
pthread_barrier_t barr;
|
||||
pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t pacing_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
u32 pkts_in_flight;
|
||||
|
||||
#endif /* XDPXCEIVER_H */
|
||||
|
||||
Reference in New Issue
Block a user