On Mon, May 11, 2020 at 10:59 PM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote: > > tests verify we get > 0 return value from bpf_trace_print() > using %pT format specifier with various modifiers/pointer > values. > > Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> > --- There is no need to use perf buffer for returning results to user-space. See prog_tests/skeleton.c and progs/test_skeleton.c for a very minimalistic and simple way to do tests like this. > .../selftests/bpf/prog_tests/trace_printk_btf.c | 83 ++++++++++++++++++++++ > .../selftests/bpf/progs/netif_receive_skb.c | 81 +++++++++++++++++++++ > 2 files changed, 164 insertions(+) > create mode 100644 tools/testing/selftests/bpf/prog_tests/trace_printk_btf.c > create mode 100644 tools/testing/selftests/bpf/progs/netif_receive_skb.c [...] > diff --git a/tools/testing/selftests/bpf/progs/netif_receive_skb.c b/tools/testing/selftests/bpf/progs/netif_receive_skb.c > new file mode 100644 > index 0000000..b5148df > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/netif_receive_skb.c > @@ -0,0 +1,81 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2020, Oracle and/or its affiliates. */ > +#include <linux/bpf.h> > +#include <stdbool.h> > +#include <bpf/bpf_helpers.h> > +#include <bpf/bpf_endian.h> > +#include <bpf/bpf_tracing.h> > + > +char _license[] SEC("license") = "GPL"; > + > +struct { > + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); > + __uint(key_size, sizeof(int)); > + __uint(value_size, sizeof(int)); > +} perf_buf_map SEC(".maps"); > + > +struct result { > + int ret; > + int subtest; > + int num_subtest; > +}; > + > +typedef struct { > + int counter; > +} atomic_t; > +typedef struct refcount_struct { > + atomic_t refs; > +} refcount_t; > + > +struct sk_buff { > + /* field names and sizes should match to those in the kernel */ > + unsigned int len, data_len; > + __u16 mac_len, hdr_len, queue_mapping; > + struct net_device *dev; > + /* order of the fields doesn't matter */ > + refcount_t users; > + unsigned char *data; > + char __pkt_type_offset[0]; > + char cb[48]; > +}; please use vmlinux.h instead of duplicating these definitions (which also will start failing, when sk_buff definition will change). > + > +#define CHECK_PRINTK(_fmt, _p, res) \ > + do { \ > + char fmt[] = _fmt; \ > + ++(res)->num_subtest; \ > + if ((res)->ret >= 0) { \ > + ++(res)->subtest; \ > + (res)->ret = bpf_trace_printk(fmt, sizeof(fmt), \ > + (_p)); \ > + } \ > + } while (0) > + > +/* TRACE_EVENT(netif_receive_skb, > + * TP_PROTO(struct sk_buff *skb), > + */ > +SEC("tp_btf/netif_receive_skb") > +int BPF_PROG(trace_netif_receive_skb, struct sk_buff *skb) > +{ > + char skb_type[] = "struct sk_buff"; > + struct __btf_ptr nullp = { .ptr = 0, .type = skb_type }; > + struct __btf_ptr p = { .ptr = skb, .type = skb_type }; > + struct result res = { 0, 0 }; > + > + CHECK_PRINTK("%pT\n", &p, &res); > + CHECK_PRINTK("%pTc\n", &p, &res); > + CHECK_PRINTK("%pTN\n", &p, &res); > + CHECK_PRINTK("%pTx\n", &p, &res); > + CHECK_PRINTK("%pT0\n", &p, &res); > + CHECK_PRINTK("%pTcNx0\n", &p, &res); > + CHECK_PRINTK("%pT\n", &nullp, &res); > + CHECK_PRINTK("%pTc\n", &nullp, &res); > + CHECK_PRINTK("%pTN\n", &nullp, &res); > + CHECK_PRINTK("%pTx\n", &nullp, &res); > + CHECK_PRINTK("%pT0\n", &nullp, &res); > + CHECK_PRINTK("%pTcNx0\n", &nullp, &res); with global variables this would be: int pT = 0; int pTc = 0; /* and so on */ then inside BPF_PROG: pT = bpf_printk("%pT\n", &p); pTc = bpf_printk("%pTc\n", &p); /* and so on */ CHECK_PRINTK isn't necessary, IMO. bpf_printk is defined in bpf_helpers.h > + > + bpf_perf_event_output(ctx, &perf_buf_map, BPF_F_CURRENT_CPU, > + &res, sizeof(res)); > + > + return 0; > +} > -- > 1.8.3.1 >