Add a test that will attach a FENTRY and FEXIT program to the XDP test program. It will also verify data from the XDP context on FENTRY and verifies the return code on exit. Signed-off-by: Eelco Chaudron <echaudro@xxxxxxxxxx> --- .../testing/selftests/bpf/prog_tests/xdp_bpf2bpf.c | 95 ++++++++++++++++++++ .../testing/selftests/bpf/progs/test_xdp_bpf2bpf.c | 44 +++++++++ 2 files changed, 139 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_bpf2bpf.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_bpf2bpf.c diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_bpf2bpf.c b/tools/testing/selftests/bpf/prog_tests/xdp_bpf2bpf.c new file mode 100644 index 000000000000..175364843ec5 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/xdp_bpf2bpf.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include <net/if.h> + +#define PROG_CNT 2 + +void test_xdp_bpf2bpf(void) +{ + const char *prog_name[PROG_CNT] = { + "fentry/_xdp_tx_iptunnel", + "fexit/_xdp_tx_iptunnel" + }; + struct bpf_link *link[PROG_CNT] = {}; + struct bpf_program *prog[PROG_CNT]; + struct bpf_map *data_map; + const int zero = 0; + u64 result[PROG_CNT]; + struct vip key4 = {.protocol = 6, .family = AF_INET}; + struct iptnl_info value4 = {.family = AF_INET}; + const char *file = "./test_xdp.o"; + struct bpf_object *obj, *tracer_obj = NULL; + char buf[128]; + struct iphdr *iph = (void *)buf + sizeof(struct ethhdr); + __u32 duration, retval, size; + int err, prog_fd, map_fd; + + /* Load XDP program to introspect */ + err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); + if (CHECK_FAIL(err)) + return; + + map_fd = bpf_find_map(__func__, obj, "vip2tnl"); + if (map_fd < 0) + goto out; + bpf_map_update_elem(map_fd, &key4, &value4, 0); + + /* Load eBPF trace program */ + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, + .attach_prog_fd = prog_fd, + ); + + tracer_obj = bpf_object__open_file("./test_xdp_bpf2bpf.o", &opts); + if (CHECK(IS_ERR_OR_NULL(tracer_obj), "obj_open", + "failed to open test_xdp_bpf2bpf: %ld\n", + PTR_ERR(tracer_obj))) + goto out; + + err = bpf_object__load(tracer_obj); + if (CHECK(err, "obj_load", "err %d\n", err)) + goto out; + + for (int i = 0; i < PROG_CNT; i++) { + prog[i] = bpf_object__find_program_by_title(tracer_obj, + prog_name[i]); + if (CHECK(!prog[i], "find_prog", "prog %s not found\n", + prog_name[i])) + goto out; + link[i] = bpf_program__attach_trace(prog[i]); + if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n")) + goto out; + } + data_map = bpf_object__find_map_by_name(tracer_obj, "test_xdp.bss"); + if (CHECK(!data_map, "find_data_map", "data map not found\n")) + goto out; + + /* Run test program */ + err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), + buf, &size, &retval, &duration); + + CHECK(err || retval != XDP_TX || size != 74 || + iph->protocol != IPPROTO_IPIP, "ipv4", + "err %d errno %d retval %d size %d\n", + err, errno, retval, size); + + /* Verify test results */ + err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, &result); + if (CHECK(err, "get_result", + "failed to get output data: %d\n", err)) + goto out; + + if (CHECK(result[0] != if_nametoindex("lo"), + "result", "%s failed err %ld\n", prog_name[0], result[0])) + goto out; + + if (CHECK(result[1] != XDP_TX, "result", "%s failed err %ld\n", + prog_name[1], result[1])) + goto out; +out: + for (int i = 0; i < PROG_CNT; i++) + if (!IS_ERR_OR_NULL(link[i])) + bpf_link__destroy(link[i]); + if (!IS_ERR_OR_NULL(tracer_obj)) + bpf_object__close(tracer_obj); + bpf_object__close(obj); +} diff --git a/tools/testing/selftests/bpf/progs/test_xdp_bpf2bpf.c b/tools/testing/selftests/bpf/progs/test_xdp_bpf2bpf.c new file mode 100644 index 000000000000..82b87b2fc4e1 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_bpf2bpf.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include "bpf_helpers.h" +#include "bpf_trace_helpers.h" + +struct net_device { + /* Structure does not need to contain all entries, + * as "preserve_access_index" will use BTF to fix this... + */ + int ifindex; +} __attribute__((preserve_access_index)); + +struct xdp_rxq_info { + /* Structure does not need to contain all entries, + * as "preserve_access_index" will use BTF to fix this... + */ + struct net_device *dev; + __u32 queue_index; +} __attribute__((preserve_access_index)); + +struct xdp_buff { + void *data; + void *data_end; + void *data_meta; + void *data_hard_start; + unsigned long handle; + struct xdp_rxq_info *rxq; +} __attribute__((preserve_access_index)); + +static volatile __u64 test_result_fentry; +BPF_TRACE_1("fentry/_xdp_tx_iptunnel", trace_on_entry, + struct xdp_buff *, xdp) +{ + test_result_fentry = xdp->rxq->dev->ifindex; + return 0; +} + +static volatile __u64 test_result_fexit; +BPF_TRACE_2("fexit/_xdp_tx_iptunnel", trace_on_exit, + struct xdp_buff*, xdp, int, ret) +{ + test_result_fexit = ret; + return 0; +}