This will be used to convert xdp_monitor to xdp_sample reorg in the next patch. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> --- samples/bpf/xdp_redirect_map_user.c | 3 +- samples/bpf/xdp_sample_kern.h | 51 +++++++++++++++++++++- samples/bpf/xdp_sample_user.c | 68 +++++++++++++++++++++++++++++ samples/bpf/xdp_sample_user.h | 10 ++++- 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c index 42893385ba96..b2c7adad99ec 100644 --- a/samples/bpf/xdp_redirect_map_user.c +++ b/samples/bpf/xdp_redirect_map_user.c @@ -76,7 +76,7 @@ static void usage(const char *prog) int main(int argc, char **argv) { int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT | - SAMPLE_EXCEPTION_CNT; + SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT; struct bpf_prog_load_attr prog_load_attr = { .prog_type = BPF_PROG_TYPE_UNSPEC, }; @@ -148,6 +148,7 @@ int main(int argc, char **argv) if (xdp_flags & XDP_FLAGS_SKB_MODE) { prog = bpf_object__find_program_by_name(obj, "xdp_redirect_map_general"); tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port_general"); + mask &= ~SAMPLE_DEVMAP_XMIT_CNT; } else { prog = bpf_object__find_program_by_name(obj, "xdp_redirect_map_native"); tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port_native"); diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h index bb809542ac20..3b85d71434d3 100644 --- a/samples/bpf/xdp_sample_kern.h +++ b/samples/bpf/xdp_sample_kern.h @@ -12,7 +12,10 @@ struct datarec { __u64 processed; __u64 dropped; __u64 issue; - __u64 xdp_pass; + union { + __u64 xdp_pass; + __u64 info; + }; __u64 xdp_drop; __u64 xdp_redirect; }; @@ -60,6 +63,13 @@ struct { __uint(max_entries, 1); } exception_cnt SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, struct datarec); + __uint(max_entries, 1); +} devmap_xmit_cnt SEC(".maps"); + /*** Trace point code ***/ /* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format @@ -218,3 +228,42 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx) return 0; } + +/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format + * Code in: kernel/include/trace/events/xdp.h + */ +struct devmap_xmit_ctx { + u64 __pad; // First 8 bytes are not accessible by bpf code + int from_ifindex; // offset:8; size:4; signed:1; + u32 act; // offset:12; size:4; signed:0; + int to_ifindex; // offset:16; size:4; signed:1; + int drops; // offset:20; size:4; signed:1; + int sent; // offset:24; size:4; signed:1; + int err; // offset:28; size:4; signed:1; +}; + +SEC("tracepoint/xdp/xdp_devmap_xmit") +int trace_xdp_devmap_xmit(struct devmap_xmit_ctx *ctx) +{ + struct datarec *rec; + u32 key = 0; + + rec = bpf_map_lookup_elem(&devmap_xmit_cnt, &key); + if (!rec) + return 0; + rec->processed += ctx->sent; + rec->dropped += ctx->drops; + + /* Record bulk events, then userspace can calc average bulk size */ + rec->info += 1; + + /* Record error cases, where no frame were sent */ + if (ctx->err) + rec->issue++; + + /* Catch API error of drv ndo_xdp_xmit sent more than count */ + if (ctx->drops < 0) + rec->issue++; + + return 1; +} diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c index be60fbddd8c7..56cd79ba303a 100644 --- a/samples/bpf/xdp_sample_user.c +++ b/samples/bpf/xdp_sample_user.c @@ -124,6 +124,7 @@ struct stats_record *alloc_stats_record(void) rec->redir_err.cpu = alloc_record_per_cpu(); rec->kthread.cpu = alloc_record_per_cpu(); rec->exception.cpu = alloc_record_per_cpu(); + rec->devmap_xmit.cpu = alloc_record_per_cpu(); for (i = 0; i < n_cpus; i++) rec->enq[i].cpu = alloc_record_per_cpu(); @@ -136,6 +137,7 @@ void free_stats_record(struct stats_record *r) for (i = 0; i < n_cpus; i++) free(r->enq[i].cpu); + free(r->devmap_xmit.cpu); free(r->exception.cpu); free(r->kthread.cpu); free(r->redir_err.cpu); @@ -192,6 +194,19 @@ static __u64 calc_errs_pps(struct datarec *r, return pps; } +static __u64 calc_info_pps(struct datarec *r, + struct datarec *p, double period_) +{ + __u64 packets = 0; + __u64 pps = 0; + + if (period_ > 0) { + packets = r->info - p->info; + pps = packets / period_; + } + return pps; +} + static void calc_xdp_pps(struct datarec *r, struct datarec *p, double *xdp_pass, double *xdp_drop, double *xdp_redirect, double period_) @@ -404,6 +419,53 @@ void sample_stats_print_cpumap_remote(struct stats_record *stats_rec, xdp_redirect); } +static void stats_print_devmap_xmit(struct stats_record *stats_rec, + struct stats_record *stats_prev, + unsigned int nr_cpus) +{ + char *fmt1 = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s %s\n"; + char *fmt2 = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f %s %s\n"; + double pps, drop, info, err; + struct record *rec, *prev; + char *err_str = ""; + char *i_str = ""; + double t; + int i; + + rec = &stats_rec->devmap_xmit; + prev = &stats_prev->devmap_xmit; + t = calc_period(rec, prev); + for (i = 0; i < nr_cpus; i++) { + struct datarec *r = &rec->cpu[i]; + struct datarec *p = &prev->cpu[i]; + + pps = calc_pps(r, p, t); + drop = calc_drop_pps(r, p, t); + info = calc_info_pps(r, p, t); + err = calc_errs_pps(r, p, t); + if (info > 0) { + i_str = "bulk-average"; + info = (pps + drop) / info; /* calc avg bulk */ + } + if (err > 0) + err_str = "drv-err"; + if (pps > 0 || drop > 0) + printf(fmt1, "devmap-xmit", i, pps, drop, info, i_str, + err_str); + } + pps = calc_pps(&rec->total, &prev->total, t); + drop = calc_drop_pps(&rec->total, &prev->total, t); + info = calc_info_pps(&rec->total, &prev->total, t); + err = calc_errs_pps(&rec->total, &prev->total, t); + if (info > 0) { + i_str = "bulk-average"; + info = (pps + drop) / info; /* calc avg bulk */ + } + if (err > 0) + err_str = "drv-err"; + printf(fmt2, "devmap-xmit", "total", pps, drop, info, i_str, err_str); +} + static int init_tracepoints(struct bpf_object *obj) { struct bpf_program *prog; @@ -472,6 +534,9 @@ void sample_stats_collect(int mask, struct stats_record *rec) if (mask & SAMPLE_EXCEPTION_CNT) map_collect_percpu(map_fds[EXCEPTION_CNT], 0, &rec->exception); + + if (mask & SAMPLE_DEVMAP_XMIT_CNT) + map_collect_percpu(map_fds[DEVMAP_XMIT_CNT], 0, &rec->devmap_xmit); } void sample_stats_print(int mask, struct stats_record *cur, @@ -497,6 +562,9 @@ void sample_stats_print(int mask, struct stats_record *cur, if (mask & SAMPLE_EXCEPTION_CNT) stats_print_exception_cnt(cur, prev, nr_cpus); + + if (mask & SAMPLE_DEVMAP_XMIT_CNT) + stats_print_devmap_xmit(cur, prev, nr_cpus); } void sample_stats_poll(int interval, int mask, char *prog_name, int use_separators) diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h index 3427baf70fc0..75a4ea4b55ad 100644 --- a/samples/bpf/xdp_sample_user.h +++ b/samples/bpf/xdp_sample_user.h @@ -9,6 +9,7 @@ enum map_type { CPUMAP_ENQUEUE_CNT, CPUMAP_KTHREAD_CNT, EXCEPTION_CNT, + DEVMAP_XMIT_CNT, NUM_MAP, }; @@ -18,6 +19,7 @@ enum tp_type { TP_CPUMAP_ENQUEUE_CNT, TP_CPUMAP_KTHREAD_CNT, TP_EXCEPTION_CNT, + TP_DEVMAP_XMIT_CNT, NUM_TP, }; @@ -27,6 +29,7 @@ enum stats_mask { SAMPLE_CPUMAP_ENQUEUE_CNT = 1U << 3, SAMPLE_CPUMAP_KTHREAD_CNT = 1U << 4, SAMPLE_EXCEPTION_CNT = 1U << 5, + SAMPLE_DEVMAP_XMIT_CNT = 1U << 6, }; static const char *const map_type_strings[] = { @@ -35,6 +38,7 @@ static const char *const map_type_strings[] = { [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt", [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt", [EXCEPTION_CNT] = "exception_cnt", + [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt", }; extern struct bpf_link *tp_links[NUM_TP]; @@ -55,7 +59,10 @@ struct datarec { __u64 processed; __u64 dropped; __u64 issue; - __u64 xdp_pass; + union { + __u64 xdp_pass; + __u64 info; + }; __u64 xdp_drop; __u64 xdp_redirect; }; @@ -71,6 +78,7 @@ struct stats_record { struct record redir_err; struct record kthread; struct record exception; + struct record devmap_xmit; struct record enq[]; }; -- 2.31.1