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