Re: [PATCH bpf-next v1 3/3] selftests/bpf: add bpf relay map selftests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Dec 27, 2023 at 6:01 PM Philo Lu <lulie@xxxxxxxxxxxxxxxxx> wrote:
>
> The operations of relay map create, update_elem, and output are tested.
> The test is borrowed from ringbuf tests, where 2 samples are written
> into the relay channel, and we get the samples by reading the files.
> Overwriting mode is also tested, where the size of relay buffer equals
> sample size and just the last sample can be seen.
>
> Signed-off-by: Philo Lu <lulie@xxxxxxxxxxxxxxxxx>
> ---
>  tools/include/uapi/linux/bpf.h                |   7 +
>  tools/testing/selftests/bpf/Makefile          |   2 +-
>  tools/testing/selftests/bpf/config            |   1 +
>  .../selftests/bpf/prog_tests/relay_map.c      | 197 ++++++++++++++++++
>  .../selftests/bpf/progs/test_relay_map.c      |  69 ++++++
>  5 files changed, 275 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/relay_map.c
>  create mode 100644 tools/testing/selftests/bpf/progs/test_relay_map.c
>
> diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> index 7f24d898efbb..1e545bfe701f 100644
> --- a/tools/include/uapi/linux/bpf.h
> +++ b/tools/include/uapi/linux/bpf.h
> @@ -951,6 +951,7 @@ enum bpf_map_type {
>         BPF_MAP_TYPE_BLOOM_FILTER,
>         BPF_MAP_TYPE_USER_RINGBUF,
>         BPF_MAP_TYPE_CGRP_STORAGE,
> +       BPF_MAP_TYPE_RELAY,
>  };
>
>  /* Note that tracing related programs such as
> @@ -1330,6 +1331,9 @@ enum {
>
>  /* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */
>         BPF_F_PATH_FD           = (1U << 14),
> +
> +/* Enable overwrite for relay map */
> +       BPF_F_OVERWRITE         = (1U << 15),
>  };
>
>  /* Flags for BPF_PROG_QUERY. */
> @@ -1401,6 +1405,9 @@ union bpf_attr {
>                  * BPF_MAP_TYPE_BLOOM_FILTER - the lowest 4 bits indicate the
>                  * number of hash functions (if 0, the bloom filter will default
>                  * to using 5 hash functions).
> +                *
> +                * BPF_MAP_TYPE_RELAY - the lowest 32 bits indicate the number of
> +                * relay subbufs (if 0, the number will be set to 8 by default).
>                  */
>                 __u64   map_extra;
>         };
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 617ae55c3bb5..8cebb3810d50 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -427,7 +427,7 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h               \
>  LSKELS := fentry_test.c fexit_test.c fexit_sleep.c atomics.c           \
>         trace_printk.c trace_vprintk.c map_ptr_kern.c                   \
>         core_kern.c core_kern_overflow.c test_ringbuf.c                 \
> -       test_ringbuf_map_key.c
> +       test_ringbuf_map_key.c test_relay_map.c
>
>  # Generate both light skeleton and libbpf skeleton for these
>  LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
> diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
> index c125c441abc7..8de1adf587f0 100644
> --- a/tools/testing/selftests/bpf/config
> +++ b/tools/testing/selftests/bpf/config
> @@ -87,3 +87,4 @@ CONFIG_VSOCKETS=y
>  CONFIG_VXLAN=y
>  CONFIG_XDP_SOCKETS=y
>  CONFIG_XFRM_INTERFACE=y
> +CONFIG_RELAY=y
> diff --git a/tools/testing/selftests/bpf/prog_tests/relay_map.c b/tools/testing/selftests/bpf/prog_tests/relay_map.c
> new file mode 100644
> index 000000000000..bd9c1e62ca78
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/relay_map.c
> @@ -0,0 +1,197 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#define _GNU_SOURCE
> +#include <linux/compiler.h>
> +#include <linux/bpf.h>
> +#include <sys/sysinfo.h>
> +#include <test_progs.h>
> +#include <sched.h>
> +
> +#include "test_relay_map.lskel.h"
> +
> +static int duration;
> +
> +/* file names in debugfs */
> +static const char dirname[]            = "relay_map_selftest";
> +static const char mapname[]            = "relay_map";
> +static const char mapname_ow[] = "relay_map_ow";
> +struct relay_sample {
> +       int pid;
> +       int seq;
> +       long value;
> +       char comm[16];
> +};
> +
> +static int sample_cnt;
> +static int overwrite;
> +
> +static void process_sample(struct relay_sample *s)
> +{
> +       ++sample_cnt;
> +
> +       switch (s->seq) {
> +       case 0:
> +               /* sample1 will not appear in overwrite mode */
> +               CHECK(overwrite != 0, "overwrite_mode",
> +                     "sample1 appears in overwrite mode\n");
> +               CHECK(s->value != 333, "sample1_value", "exp %ld, got %ld\n",
> +                     333L, s->value);
> +               break;
> +       case 1:
> +               CHECK(s->value != 777, "sample2_value", "exp %ld, got %ld\n",
> +                     777L, s->value);
> +               break;
> +       default:
> +               break;
> +       }
> +}
> +
> +static int relaymap_read(const char *mapname)
> +{
> +       int cpu = libbpf_num_possible_cpus();
> +       char name[NAME_MAX];
> +       struct relay_sample data;
> +       int maxloop;
> +       FILE *fp;
> +
> +       for (int i = 0; i < cpu; ++i) {
> +               sprintf(name, "/sys/kernel/debug/%s/%s%d", dirname, mapname, i);
> +               fp = fopen(name, "r");

fclose() is missed.

> +               if (CHECK(!fp, "fopen", "relay file open failed\n"))
> +                       return -1;
> +
> +               maxloop = 0;
> +               while (fread(&data, sizeof(data), 1, fp)) {
> +                       process_sample(&data);
> +
> +                       /* just 2 samples output */
> +                       if (++maxloop > 2)
> +                               return -1;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static struct test_relay_map_lskel *skel;
> +
> +static void trigger_samples(void)
> +{
> +       skel->bss->dropped = 0;
> +       skel->bss->total = 0;
> +       skel->bss->seq = 0;
> +
> +       /* trigger exactly two samples */
> +       skel->bss->value = 333;
> +       syscall(__NR_getpgid);
> +       skel->bss->value = 777;
> +       syscall(__NR_getpgid);
> +}
> +
> +static void relaymap_subtest(void)
> +{
> +       int err, map_fd;
> +
> +       skel = test_relay_map_lskel__open();
> +       if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
> +               return;
> +
> +       /* setup relay param */
> +       skel->maps.relay_map.max_entries = 1024;
> +
> +       err = test_relay_map_lskel__load(skel);
> +       if (CHECK(err, "skel_load", "skeleton load failed\n"))
> +               goto cleanup;
> +
> +       /* only trigger BPF program for current process */
> +       skel->bss->pid = getpid();
> +
> +       /* turn off overwrite */
> +       skel->bss->overwrite_enable = 0;
> +       overwrite = skel->bss->overwrite_enable;
> +
> +       err = test_relay_map_lskel__attach(skel);
> +       if (CHECK(err, "skel_attach", "skeleton attachment failed: %d\n", err))
> +               goto cleanup;
> +
> +       /* before file setup - output failed */
> +       trigger_samples();
> +       CHECK(skel->bss->dropped != 2, "err_dropped", "exp %ld, got %ld\n",
> +             0L, skel->bss->dropped);
> +       CHECK(skel->bss->total != 2, "err_total", "exp %ld, got %ld\n",
> +             2L, skel->bss->total);
> +
> +       /* after file setup - output succ */
> +       map_fd = skel->maps.relay_map.map_fd;
> +       err = bpf_map_update_elem(map_fd, NULL, dirname, 0);
> +       if (CHECK(err, "map_update", "map update failed: %d\n", err))
> +               goto cleanup;
> +       trigger_samples();
> +       CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",
> +             0L, skel->bss->dropped);
> +       CHECK(skel->bss->total != 2, "err_total", "exp %ld, got %ld\n",
> +             2L, skel->bss->total);
> +
> +       sample_cnt = 0;
> +       err = relaymap_read(mapname);
> +       CHECK(sample_cnt != 2, "sample_cnt", "exp %d samples, got %d\n",
> +                  2, sample_cnt);
> +
> +       test_relay_map_lskel__detach(skel);
> +cleanup:
> +       test_relay_map_lskel__destroy(skel);
> +}
> +
> +static void relaymap_overwrite_subtest(void)
> +{
> +       int err, map_fd;
> +
> +       skel = test_relay_map_lskel__open();
> +       if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
> +               return;
> +
> +       /* To test overwrite mode, we create subbuf of one-sample size */
> +       skel->maps.relay_map_ow.max_entries = sizeof(struct relay_sample);
> +
> +       err = test_relay_map_lskel__load(skel);
> +       if (CHECK(err, "skel_load", "skeleton load failed\n"))
> +               goto cleanup;
> +
> +       /* only trigger BPF program for current process */
> +       skel->bss->pid = getpid();
> +
> +       /* turn on overwrite */
> +       skel->bss->overwrite_enable = 1;
> +       overwrite = skel->bss->overwrite_enable;
> +
> +       err = test_relay_map_lskel__attach(skel);
> +       if (CHECK(err, "skel_attach", "skeleton attachment failed: %d\n", err))
> +               goto cleanup;
> +
> +       map_fd = skel->maps.relay_map_ow.map_fd;
> +       err = bpf_map_update_elem(map_fd, NULL, dirname, 0);
> +       if (CHECK(err, "map_update", "map update failed: %d\n", err))
> +               goto cleanup;
> +       trigger_samples();
> +       /* relay_write never fails whether overwriting or not */
> +       CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",
> +             0L, skel->bss->dropped);
> +       CHECK(skel->bss->total != 2, "err_total", "exp %ld, got %ld\n",
> +             2L, skel->bss->total);
> +
> +       /* 2 samples are output, but only the last (val=777) could be seen */
> +       sample_cnt = 0;
> +       err = relaymap_read(mapname_ow);
> +       CHECK(sample_cnt != 1, "sample_cnt", "exp %d samples, got %d\n",
> +                  1, sample_cnt);
> +
> +       test_relay_map_lskel__detach(skel);
> +cleanup:
> +       test_relay_map_lskel__destroy(skel);
> +}
> +
> +void test_relaymap(void)
> +{
> +       if (test__start_subtest("relaymap"))
> +               relaymap_subtest();
> +       if (test__start_subtest("relaymap_overwrite"))
> +               relaymap_overwrite_subtest();
> +}
> diff --git a/tools/testing/selftests/bpf/progs/test_relay_map.c b/tools/testing/selftests/bpf/progs/test_relay_map.c
> new file mode 100644
> index 000000000000..1adf1be8e125
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/test_relay_map.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_misc.h"
> +
> +char _license[] SEC("license") = "GPL";
> +
> +extern int bpf_relay_output(struct bpf_map *map, void *data,
> +                                     __u64 data__sz, __u32 flags) __ksym;
> +
> +struct relay_sample {
> +       int pid;
> +       int seq;
> +       long value;
> +       char comm[16];
> +};
> +
> +struct {
> +       __uint(type, BPF_MAP_TYPE_RELAY);
> +       __uint(max_entries, 1024);
> +} relay_map SEC(".maps");
> +
> +struct {
> +       __uint(type, BPF_MAP_TYPE_RELAY);
> +       __uint(map_flags, BPF_F_OVERWRITE);
> +       __uint(max_entries, 1024);
> +       __uint(map_extra, 1);
> +} relay_map_ow SEC(".maps");
> +
> +/* inputs */
> +int pid = 0;
> +long value = 0;
> +int overwrite_enable = 0;
> +
> +/* outputs */
> +long total = 0;
> +long dropped = 0;
> +
> +/* inner state */
> +long seq = 0;
> +
> +SEC("fentry/" SYS_PREFIX "sys_getpgid")
> +int test_bpf_relaymap(void *ctx)
> +{
> +       int cur_pid = bpf_get_current_pid_tgid() >> 32;
> +       struct relay_sample sample;
> +       int ret = 0;
> +
> +       if (cur_pid != pid)
> +               return 0;
> +
> +       sample.pid = pid;
> +       bpf_get_current_comm(sample.comm, sizeof(sample.comm));
> +       sample.value = value;
> +       sample.seq = seq++;
> +       __sync_fetch_and_add(&total, 1);
> +
> +       if (overwrite_enable)
> +               ret = bpf_relay_output((struct bpf_map *)&relay_map_ow,
> +                                     &sample, sizeof(sample), 0);
> +       else
> +               ret = bpf_relay_output((struct bpf_map *)&relay_map,
> +                                     &sample, sizeof(sample), 0);
> +
> +       if (ret)
> +               __sync_fetch_and_add(&dropped, 1);
> +
> +       return 0;
> +}
> --
> 2.32.0.3.g01195cf9f
>


-- 
Regards
Yafang





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux