* [PATCH RFC bpf-next 01/15] samples: bpf: fix a couple of NULL dereferences
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 02/15] samples: bpf: fix a couple of warnings Kumar Kartikeya Dwivedi
` (13 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
When giving it just one ifname instead of two, it accesses argv[optind + 1],
which is out of bounds (as argc < optind + 1).
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_redirect_map_user.c | 4 ++--
samples/bpf/xdp_redirect_user.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index 0e8192688dfc..ad3cdc4c07d3 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -169,8 +169,8 @@ int main(int argc, char **argv)
return 1;
}
- if (optind == argc) {
- printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]);
+ if (argc <= optind + 1) {
+ usage(basename(argv[0]));
return 1;
}
diff --git a/samples/bpf/xdp_redirect_user.c b/samples/bpf/xdp_redirect_user.c
index 41d705c3a1f7..4e310660632b 100644
--- a/samples/bpf/xdp_redirect_user.c
+++ b/samples/bpf/xdp_redirect_user.c
@@ -130,8 +130,8 @@ int main(int argc, char **argv)
if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
xdp_flags |= XDP_FLAGS_DRV_MODE;
- if (optind == argc) {
- printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]);
+ if (argc <= optind + 1) {
+ usage(basename(argv[0]));
return 1;
}
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 02/15] samples: bpf: fix a couple of warnings
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 01/15] samples: bpf: fix a couple of NULL dereferences Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 03/15] samples: bpf: split out common bpf progs to its own file Kumar Kartikeya Dwivedi
` (12 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
cookie_uid_helper_example.c: In function ‘main’:
cookie_uid_helper_example.c:178:69: warning: ‘ -j ACCEPT’ directive
writing 10 bytes into a region of size between 8 and 58
[-Wformat-overflow=]
178 | sprintf(rules, "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT",
| ^~~~~~~~~~
/home/kkd/src/linux/samples/bpf/cookie_uid_helper_example.c:178:9: note:
‘sprintf’ output between 53 and 103 bytes into a destination of size 100
178 | sprintf(rules, "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179 | file);
| ~~~~~
Fix by using snprintf and a sufficiently sized buffer.
tracex4_user.c:35:15: warning: ‘write’ reading 12 bytes from a region of
size 11 [-Wstringop-overread]
35 | key = write(1, "\e[1;1H\e[2J", 12); /* clear screen */
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use size as 11.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/cookie_uid_helper_example.c | 12 +++++++++---
samples/bpf/tracex4_user.c | 2 +-
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/samples/bpf/cookie_uid_helper_example.c b/samples/bpf/cookie_uid_helper_example.c
index cc3bce8d3aac..30fdcd664da2 100644
--- a/samples/bpf/cookie_uid_helper_example.c
+++ b/samples/bpf/cookie_uid_helper_example.c
@@ -1,3 +1,4 @@
+
/* This test is a demo of using get_socket_uid and get_socket_cookie
* helper function to do per socket based network traffic monitoring.
* It requires iptables version higher then 1.6.1. to load pinned eBPF
@@ -167,7 +168,7 @@ static void prog_load(void)
static void prog_attach_iptables(char *file)
{
int ret;
- char rules[100];
+ char rules[256];
if (bpf_obj_pin(prog_fd, file))
error(1, errno, "bpf_obj_pin");
@@ -175,8 +176,13 @@ static void prog_attach_iptables(char *file)
printf("file path too long: %s\n", file);
exit(1);
}
- sprintf(rules, "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT",
- file);
+ ret = snprintf(rules, sizeof(rules),
+ "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT",
+ file);
+ if (ret < 0 || ret >= sizeof(rules)) {
+ printf("error constructing iptables command\n");
+ exit(1);
+ }
ret = system(rules);
if (ret < 0) {
printf("iptables rule update failed: %d/n", WEXITSTATUS(ret));
diff --git a/samples/bpf/tracex4_user.c b/samples/bpf/tracex4_user.c
index cea399424bca..566e6440e8c2 100644
--- a/samples/bpf/tracex4_user.c
+++ b/samples/bpf/tracex4_user.c
@@ -32,7 +32,7 @@ static void print_old_objects(int fd)
__u64 key, next_key;
struct pair v;
- key = write(1, "\e[1;1H\e[2J", 12); /* clear screen */
+ key = write(1, "\e[1;1H\e[2J", 11); /* clear screen */
key = -1;
while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 03/15] samples: bpf: split out common bpf progs to its own file
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 01/15] samples: bpf: fix a couple of NULL dereferences Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 02/15] samples: bpf: fix a couple of warnings Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-30 3:05 ` Andrii Nakryiko
2021-05-28 23:52 ` [PATCH RFC bpf-next 04/15] samples: bpf: refactor generic parts out of xdp_redirect_cpu_user Kumar Kartikeya Dwivedi
` (11 subsequent siblings)
14 siblings, 1 reply; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This is done to later reuse these in a way that can be shared
among multiple samples.
We are using xdp_redirect_cpu_kern.c as a base to build further support on
top (mostly adding a few other things missing that xdp_monitor does in
subsequent patches).
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_sample_kern.h | 220 ++++++++++++++++++++++++++++++++++
1 file changed, 220 insertions(+)
create mode 100644 samples/bpf/xdp_sample_kern.h
diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
new file mode 100644
index 000000000000..bb809542ac20
--- /dev/null
+++ b/samples/bpf/xdp_sample_kern.h
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/* GPLv2, Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc. */
+#pragma once
+
+#include <uapi/linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+#define MAX_CPUS 64
+
+/* Common stats data record to keep userspace more simple */
+struct datarec {
+ __u64 processed;
+ __u64 dropped;
+ __u64 issue;
+ __u64 xdp_pass;
+ __u64 xdp_drop;
+ __u64 xdp_redirect;
+};
+
+/* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
+ * feedback. Redirect TX errors can be caught via a tracepoint.
+ */
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, u32);
+ __type(value, struct datarec);
+ __uint(max_entries, 1);
+} rx_cnt SEC(".maps");
+
+/* Used by trace point */
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, u32);
+ __type(value, struct datarec);
+ __uint(max_entries, 2);
+ /* TODO: have entries for all possible errno's */
+} redirect_err_cnt SEC(".maps");
+
+/* Used by trace point */
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, u32);
+ __type(value, struct datarec);
+ __uint(max_entries, MAX_CPUS);
+} cpumap_enqueue_cnt SEC(".maps");
+
+/* Used by trace point */
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, u32);
+ __type(value, struct datarec);
+ __uint(max_entries, 1);
+} cpumap_kthread_cnt SEC(".maps");
+
+/* Used by trace point */
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, u32);
+ __type(value, struct datarec);
+ __uint(max_entries, 1);
+} exception_cnt SEC(".maps");
+
+/*** Trace point code ***/
+
+/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
+ * Code in: kernel/include/trace/events/xdp.h
+ */
+struct xdp_redirect_ctx {
+ u64 __pad; // First 8 bytes are not accessible by bpf code
+ int prog_id; // offset:8; size:4; signed:1;
+ u32 act; // offset:12 size:4; signed:0;
+ int ifindex; // offset:16 size:4; signed:1;
+ int err; // offset:20 size:4; signed:1;
+ int to_ifindex; // offset:24 size:4; signed:1;
+ u32 map_id; // offset:28 size:4; signed:0;
+ int map_index; // offset:32 size:4; signed:1;
+}; // offset:36
+
+enum {
+ XDP_REDIRECT_SUCCESS = 0,
+ XDP_REDIRECT_ERROR = 1
+};
+
+static __always_inline
+int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
+{
+ u32 key = XDP_REDIRECT_ERROR;
+ struct datarec *rec;
+ int err = ctx->err;
+
+ if (!err)
+ key = XDP_REDIRECT_SUCCESS;
+
+ rec = bpf_map_lookup_elem(&redirect_err_cnt, &key);
+ if (!rec)
+ return 0;
+ rec->dropped += 1;
+
+ return 0; /* Indicate event was filtered (no further processing)*/
+ /*
+ * Returning 1 here would allow e.g. a perf-record tracepoint
+ * to see and record these events, but it doesn't work well
+ * in-practice as stopping perf-record also unload this
+ * bpf_prog. Plus, there is additional overhead of doing so.
+ */
+}
+
+SEC("tracepoint/xdp/xdp_redirect_err")
+int trace_xdp_redirect_err(struct xdp_redirect_ctx *ctx)
+{
+ return xdp_redirect_collect_stat(ctx);
+}
+
+SEC("tracepoint/xdp/xdp_redirect_map_err")
+int trace_xdp_redirect_map_err(struct xdp_redirect_ctx *ctx)
+{
+ return xdp_redirect_collect_stat(ctx);
+}
+
+/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
+ * Code in: kernel/include/trace/events/xdp.h
+ */
+struct xdp_exception_ctx {
+ u64 __pad; // First 8 bytes are not accessible by bpf code
+ int prog_id; // offset:8; size:4; signed:1;
+ u32 act; // offset:12; size:4; signed:0;
+ int ifindex; // offset:16; size:4; signed:1;
+};
+
+SEC("tracepoint/xdp/xdp_exception")
+int trace_xdp_exception(struct xdp_exception_ctx *ctx)
+{
+ struct datarec *rec;
+ u32 key = 0;
+
+ rec = bpf_map_lookup_elem(&exception_cnt, &key);
+ if (!rec)
+ return 1;
+ rec->dropped += 1;
+
+ return 0;
+}
+
+/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
+ * Code in: kernel/include/trace/events/xdp.h
+ */
+struct cpumap_enqueue_ctx {
+ u64 __pad; // First 8 bytes are not accessible by bpf code
+ int map_id; // offset:8; size:4; signed:1;
+ u32 act; // offset:12; size:4; signed:0;
+ int cpu; // offset:16; size:4; signed:1;
+ unsigned int drops; // offset:20; size:4; signed:0;
+ unsigned int processed; // offset:24; size:4; signed:0;
+ int to_cpu; // offset:28; size:4; signed:1;
+};
+
+SEC("tracepoint/xdp/xdp_cpumap_enqueue")
+int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
+{
+ u32 to_cpu = ctx->to_cpu;
+ struct datarec *rec;
+
+ if (to_cpu >= MAX_CPUS)
+ return 1;
+
+ rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &to_cpu);
+ if (!rec)
+ return 0;
+ rec->processed += ctx->processed;
+ rec->dropped += ctx->drops;
+
+ /* Record bulk events, then userspace can calc average bulk size */
+ if (ctx->processed > 0)
+ rec->issue += 1;
+
+ /* Inception: It's possible to detect overload situations, via
+ * this tracepoint. This can be used for creating a feedback
+ * loop to XDP, which can take appropriate actions to mitigate
+ * this overload situation.
+ */
+ return 0;
+}
+
+/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_kthread/format
+ * Code in: kernel/include/trace/events/xdp.h
+ */
+struct cpumap_kthread_ctx {
+ u64 __pad; // First 8 bytes are not accessible
+ int map_id; // offset:8; size:4; signed:1;
+ u32 act; // offset:12; size:4; signed:0;
+ int cpu; // offset:16; size:4; signed:1;
+ unsigned int drops; // offset:20; size:4; signed:0;
+ unsigned int processed; // offset:24; size:4; signed:0;
+ int sched; // offset:28; size:4; signed:1;
+ unsigned int xdp_pass; // offset:32; size:4; signed:0;
+ unsigned int xdp_drop; // offset:36; size:4; signed:0;
+ unsigned int xdp_redirect; // offset:40; size:4; signed:0;
+};
+
+SEC("tracepoint/xdp/xdp_cpumap_kthread")
+int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx)
+{
+ struct datarec *rec;
+ u32 key = 0;
+
+ rec = bpf_map_lookup_elem(&cpumap_kthread_cnt, &key);
+ if (!rec)
+ return 0;
+ rec->processed += ctx->processed;
+ rec->dropped += ctx->drops;
+ rec->xdp_pass += ctx->xdp_pass;
+ rec->xdp_drop += ctx->xdp_drop;
+ rec->xdp_redirect += ctx->xdp_redirect;
+
+ /* Count times kthread yielded CPU via schedule call */
+ if (ctx->sched)
+ rec->issue++;
+
+ return 0;
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH RFC bpf-next 03/15] samples: bpf: split out common bpf progs to its own file
2021-05-28 23:52 ` [PATCH RFC bpf-next 03/15] samples: bpf: split out common bpf progs to its own file Kumar Kartikeya Dwivedi
@ 2021-05-30 3:05 ` Andrii Nakryiko
0 siblings, 0 replies; 18+ messages in thread
From: Andrii Nakryiko @ 2021-05-30 3:05 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen,
Networking
On Fri, May 28, 2021 at 4:53 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> This is done to later reuse these in a way that can be shared
> among multiple samples.
>
> We are using xdp_redirect_cpu_kern.c as a base to build further support on
> top (mostly adding a few other things missing that xdp_monitor does in
> subsequent patches).
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
> samples/bpf/xdp_sample_kern.h | 220 ++++++++++++++++++++++++++++++++++
> 1 file changed, 220 insertions(+)
> create mode 100644 samples/bpf/xdp_sample_kern.h
>
> diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
instead of doing it as a header, can you please use BPF static linking
instead? I think that's a better approach and a good showcase for
anyone that would like to use static linking for their BPF programs
> new file mode 100644
> index 000000000000..bb809542ac20
> --- /dev/null
> +++ b/samples/bpf/xdp_sample_kern.h
> @@ -0,0 +1,220 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* GPLv2, Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc. */
> +#pragma once
> +
> +#include <uapi/linux/bpf.h>
> +#include <bpf/bpf_helpers.h>
> +
> +#define MAX_CPUS 64
> +
> +/* Common stats data record to keep userspace more simple */
> +struct datarec {
> + __u64 processed;
> + __u64 dropped;
> + __u64 issue;
> + __u64 xdp_pass;
> + __u64 xdp_drop;
> + __u64 xdp_redirect;
> +};
> +
> +/* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
> + * feedback. Redirect TX errors can be caught via a tracepoint.
> + */
> +struct {
> + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
> + __type(key, u32);
> + __type(value, struct datarec);
> + __uint(max_entries, 1);
> +} rx_cnt SEC(".maps");
> +
> +/* Used by trace point */
> +struct {
> + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
> + __type(key, u32);
> + __type(value, struct datarec);
> + __uint(max_entries, 2);
> + /* TODO: have entries for all possible errno's */
> +} redirect_err_cnt SEC(".maps");
> +
> +/* Used by trace point */
> +struct {
> + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
> + __type(key, u32);
> + __type(value, struct datarec);
> + __uint(max_entries, MAX_CPUS);
> +} cpumap_enqueue_cnt SEC(".maps");
One way to squeeze a bit more performance would be to instead use
global variables instead of maps:
struct datarec cpu_map_enqueue_cnts[MAX_CPUS][MAX_CPUS];
and other PERCPU_ARRAY arrays could be just one-dimensional arrays.
You'd need to ensure each value sits on its own cache-line, of course.
> +
> +/* Used by trace point */
> +struct {
> + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
> + __type(key, u32);
> + __type(value, struct datarec);
> + __uint(max_entries, 1);
> +} cpumap_kthread_cnt SEC(".maps");
> +
[...]
> +
> +/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
> + * Code in: kernel/include/trace/events/xdp.h
> + */
> +struct cpumap_enqueue_ctx {
> + u64 __pad; // First 8 bytes are not accessible by bpf code
> + int map_id; // offset:8; size:4; signed:1;
> + u32 act; // offset:12; size:4; signed:0;
> + int cpu; // offset:16; size:4; signed:1;
> + unsigned int drops; // offset:20; size:4; signed:0;
> + unsigned int processed; // offset:24; size:4; signed:0;
> + int to_cpu; // offset:28; size:4; signed:1;
> +};
if you used vmlinux.h, this is already in there as struct
trace_event_raw_xdp_cpumap_enqueue, similarly for other tracepoints
> +
> +SEC("tracepoint/xdp/xdp_cpumap_enqueue")
> +int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
> +{
> + u32 to_cpu = ctx->to_cpu;
> + struct datarec *rec;
> +
> + if (to_cpu >= MAX_CPUS)
> + return 1;
> +
> + rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &to_cpu);
> + if (!rec)
> + return 0;
> + rec->processed += ctx->processed;
> + rec->dropped += ctx->drops;
> +
> + /* Record bulk events, then userspace can calc average bulk size */
> + if (ctx->processed > 0)
> + rec->issue += 1;
> +
> + /* Inception: It's possible to detect overload situations, via
> + * this tracepoint. This can be used for creating a feedback
> + * loop to XDP, which can take appropriate actions to mitigate
> + * this overload situation.
> + */
> + return 0;
> +}
> +
[...]
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 04/15] samples: bpf: refactor generic parts out of xdp_redirect_cpu_user
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (2 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 03/15] samples: bpf: split out common bpf progs to its own file Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 05/15] samples: bpf: convert xdp_redirect_map to use xdp_samples Kumar Kartikeya Dwivedi
` (10 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This will be used as a common core for multiple samples.
Also add a couple of helpers:
get_driver_name - Used to print the driver name for ifindex
get_mac_addr - Used to get the mac address for ifindex
This change also converts xdp_redirect_cpu to use the new xdp_sample
helpers.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/Makefile | 2 +-
samples/bpf/xdp_redirect_cpu_kern.c | 213 +---------
samples/bpf/xdp_redirect_cpu_user.c | 560 ++------------------------
samples/bpf/xdp_sample_user.c | 588 ++++++++++++++++++++++++++++
samples/bpf/xdp_sample_user.h | 101 +++++
5 files changed, 730 insertions(+), 734 deletions(-)
create mode 100644 samples/bpf/xdp_sample_user.c
create mode 100644 samples/bpf/xdp_sample_user.h
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 520434ea966f..c0c02e12e28b 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -101,7 +101,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
xdp_redirect-objs := xdp_redirect_user.o
xdp_redirect_map-objs := xdp_redirect_map_user.o
xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o
-xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o
+xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_sample_user.o
xdp_monitor-objs := xdp_monitor_user.o
xdp_rxq_info-objs := xdp_rxq_info_user.o
syscall_tp-objs := syscall_tp_user.o
diff --git a/samples/bpf/xdp_redirect_cpu_kern.c b/samples/bpf/xdp_redirect_cpu_kern.c
index 8255025dea97..06cc37f0289c 100644
--- a/samples/bpf/xdp_redirect_cpu_kern.c
+++ b/samples/bpf/xdp_redirect_cpu_kern.c
@@ -14,6 +14,7 @@
#include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "hash_func01.h"
+#include "xdp_sample_kern.h"
#define MAX_CPUS NR_CPUS
@@ -25,51 +26,6 @@ struct {
__uint(max_entries, MAX_CPUS);
} cpu_map SEC(".maps");
-/* Common stats data record to keep userspace more simple */
-struct datarec {
- __u64 processed;
- __u64 dropped;
- __u64 issue;
- __u64 xdp_pass;
- __u64 xdp_drop;
- __u64 xdp_redirect;
-};
-
-/* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
- * feedback. Redirect TX errors can be caught via a tracepoint.
- */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 1);
-} rx_cnt SEC(".maps");
-
-/* Used by trace point */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 2);
- /* TODO: have entries for all possible errno's */
-} redirect_err_cnt SEC(".maps");
-
-/* Used by trace point */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, MAX_CPUS);
-} cpumap_enqueue_cnt SEC(".maps");
-
-/* Used by trace point */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 1);
-} cpumap_kthread_cnt SEC(".maps");
-
/* Set of maps controlling available CPU, and for iterating through
* selectable redirect CPUs.
*/
@@ -92,14 +48,6 @@ struct {
__uint(max_entries, 1);
} cpus_iterator SEC(".maps");
-/* Used by trace point */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 1);
-} exception_cnt SEC(".maps");
-
/* Helper parse functions */
/* Parse Ethernet layer 2, extract network layer 3 offset and protocol
@@ -569,162 +517,3 @@ int xdp_prognum5_lb_hash_ip_pairs(struct xdp_md *ctx)
}
char _license[] SEC("license") = "GPL";
-
-/*** Trace point code ***/
-
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_redirect_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12 size:4; signed:0;
- int ifindex; // offset:16 size:4; signed:1;
- int err; // offset:20 size:4; signed:1;
- int to_ifindex; // offset:24 size:4; signed:1;
- u32 map_id; // offset:28 size:4; signed:0;
- int map_index; // offset:32 size:4; signed:1;
-}; // offset:36
-
-enum {
- XDP_REDIRECT_SUCCESS = 0,
- XDP_REDIRECT_ERROR = 1
-};
-
-static __always_inline
-int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
-{
- u32 key = XDP_REDIRECT_ERROR;
- struct datarec *rec;
- int err = ctx->err;
-
- if (!err)
- key = XDP_REDIRECT_SUCCESS;
-
- rec = bpf_map_lookup_elem(&redirect_err_cnt, &key);
- if (!rec)
- return 0;
- rec->dropped += 1;
-
- return 0; /* Indicate event was filtered (no further processing)*/
- /*
- * Returning 1 here would allow e.g. a perf-record tracepoint
- * to see and record these events, but it doesn't work well
- * in-practice as stopping perf-record also unload this
- * bpf_prog. Plus, there is additional overhead of doing so.
- */
-}
-
-SEC("tracepoint/xdp/xdp_redirect_err")
-int trace_xdp_redirect_err(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-SEC("tracepoint/xdp/xdp_redirect_map_err")
-int trace_xdp_redirect_map_err(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_exception_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int ifindex; // offset:16; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_exception")
-int trace_xdp_exception(struct xdp_exception_ctx *ctx)
-{
- struct datarec *rec;
- u32 key = 0;
-
- rec = bpf_map_lookup_elem(&exception_cnt, &key);
- if (!rec)
- return 1;
- rec->dropped += 1;
-
- return 0;
-}
-
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_enqueue_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int to_cpu; // offset:28; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_enqueue")
-int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
-{
- u32 to_cpu = ctx->to_cpu;
- struct datarec *rec;
-
- if (to_cpu >= MAX_CPUS)
- return 1;
-
- rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &to_cpu);
- if (!rec)
- return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
-
- /* Record bulk events, then userspace can calc average bulk size */
- if (ctx->processed > 0)
- rec->issue += 1;
-
- /* Inception: It's possible to detect overload situations, via
- * this tracepoint. This can be used for creating a feedback
- * loop to XDP, which can take appropriate actions to mitigate
- * this overload situation.
- */
- return 0;
-}
-
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_kthread/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_kthread_ctx {
- u64 __pad; // First 8 bytes are not accessible
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int sched; // offset:28; size:4; signed:1;
- unsigned int xdp_pass; // offset:32; size:4; signed:0;
- unsigned int xdp_drop; // offset:36; size:4; signed:0;
- unsigned int xdp_redirect; // offset:40; size:4; signed:0;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_kthread")
-int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx)
-{
- struct datarec *rec;
- u32 key = 0;
-
- rec = bpf_map_lookup_elem(&cpumap_kthread_cnt, &key);
- if (!rec)
- return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
- rec->xdp_pass += ctx->xdp_pass;
- rec->xdp_drop += ctx->xdp_drop;
- rec->xdp_redirect += ctx->xdp_redirect;
-
- /* Count times kthread yielded CPU via schedule call */
- if (ctx->sched)
- rec->issue++;
-
- return 0;
-}
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 576411612523..6dbed962a2e2 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -22,59 +22,21 @@ static const char *__doc__ =
#include <arpa/inet.h>
#include <linux/if_link.h>
-/* How many xdp_progs are defined in _kern.c */
-#define MAX_PROG 6
-
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_util.h"
+#include "xdp_sample_user.h"
static int ifindex = -1;
static char ifname_buf[IF_NAMESIZE];
static char *ifname;
static __u32 prog_id;
+static int map_fd;
+static int avail_fd;
+static int count_fd;
static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
-static int n_cpus;
-
-enum map_type {
- CPU_MAP,
- RX_CNT,
- REDIRECT_ERR_CNT,
- CPUMAP_ENQUEUE_CNT,
- CPUMAP_KTHREAD_CNT,
- CPUS_AVAILABLE,
- CPUS_COUNT,
- CPUS_ITERATOR,
- EXCEPTION_CNT,
-};
-
-static const char *const map_type_strings[] = {
- [CPU_MAP] = "cpu_map",
- [RX_CNT] = "rx_cnt",
- [REDIRECT_ERR_CNT] = "redirect_err_cnt",
- [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
- [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
- [CPUS_AVAILABLE] = "cpus_available",
- [CPUS_COUNT] = "cpus_count",
- [CPUS_ITERATOR] = "cpus_iterator",
- [EXCEPTION_CNT] = "exception_cnt",
-};
-
-#define NUM_TP 5
-#define NUM_MAP 9
-struct bpf_link *tp_links[NUM_TP] = {};
-static int map_fds[NUM_MAP];
-static int tp_cnt = 0;
-
-/* Exit return codes */
-#define EXIT_OK 0
-#define EXIT_FAIL 1
-#define EXIT_FAIL_OPTION 2
-#define EXIT_FAIL_XDP 3
-#define EXIT_FAIL_BPF 4
-#define EXIT_FAIL_MEM 5
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
@@ -115,11 +77,8 @@ static void int_exit(int sig)
printf("program on interface changed, not removing\n");
}
}
- /* Detach tracepoints */
- while (tp_cnt)
- bpf_link__destroy(tp_links[--tp_cnt]);
- exit(EXIT_OK);
+ sample_exit(EXIT_OK);
}
static void print_avail_progs(struct bpf_object *obj)
@@ -155,423 +114,6 @@ static void usage(char *argv[], struct bpf_object *obj)
printf("\n");
}
-/* gettime returns the current time of day in nanoseconds.
- * Cost: clock_gettime (ns) => 26ns (CLOCK_MONOTONIC)
- * clock_gettime (ns) => 9ns (CLOCK_MONOTONIC_COARSE)
- */
-#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
-static __u64 gettime(void)
-{
- struct timespec t;
- int res;
-
- res = clock_gettime(CLOCK_MONOTONIC, &t);
- if (res < 0) {
- fprintf(stderr, "Error with gettimeofday! (%i)\n", res);
- exit(EXIT_FAIL);
- }
- return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
-}
-
-/* Common stats data record shared with _kern.c */
-struct datarec {
- __u64 processed;
- __u64 dropped;
- __u64 issue;
- __u64 xdp_pass;
- __u64 xdp_drop;
- __u64 xdp_redirect;
-};
-struct record {
- __u64 timestamp;
- struct datarec total;
- struct datarec *cpu;
-};
-struct stats_record {
- struct record rx_cnt;
- struct record redir_err;
- struct record kthread;
- struct record exception;
- struct record enq[];
-};
-
-static bool map_collect_percpu(int fd, __u32 key, struct record *rec)
-{
- /* For percpu maps, userspace gets a value per possible CPU */
- unsigned int nr_cpus = bpf_num_possible_cpus();
- struct datarec values[nr_cpus];
- __u64 sum_xdp_redirect = 0;
- __u64 sum_xdp_pass = 0;
- __u64 sum_xdp_drop = 0;
- __u64 sum_processed = 0;
- __u64 sum_dropped = 0;
- __u64 sum_issue = 0;
- int i;
-
- if ((bpf_map_lookup_elem(fd, &key, values)) != 0) {
- fprintf(stderr,
- "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
- return false;
- }
- /* Get time as close as possible to reading map contents */
- rec->timestamp = gettime();
-
- /* Record and sum values from each CPU */
- for (i = 0; i < nr_cpus; i++) {
- rec->cpu[i].processed = values[i].processed;
- sum_processed += values[i].processed;
- rec->cpu[i].dropped = values[i].dropped;
- sum_dropped += values[i].dropped;
- rec->cpu[i].issue = values[i].issue;
- sum_issue += values[i].issue;
- rec->cpu[i].xdp_pass = values[i].xdp_pass;
- sum_xdp_pass += values[i].xdp_pass;
- rec->cpu[i].xdp_drop = values[i].xdp_drop;
- sum_xdp_drop += values[i].xdp_drop;
- rec->cpu[i].xdp_redirect = values[i].xdp_redirect;
- sum_xdp_redirect += values[i].xdp_redirect;
- }
- rec->total.processed = sum_processed;
- rec->total.dropped = sum_dropped;
- rec->total.issue = sum_issue;
- rec->total.xdp_pass = sum_xdp_pass;
- rec->total.xdp_drop = sum_xdp_drop;
- rec->total.xdp_redirect = sum_xdp_redirect;
- return true;
-}
-
-static struct datarec *alloc_record_per_cpu(void)
-{
- unsigned int nr_cpus = bpf_num_possible_cpus();
- struct datarec *array;
-
- array = calloc(nr_cpus, sizeof(struct datarec));
- if (!array) {
- fprintf(stderr, "Mem alloc error (nr_cpus:%u)\n", nr_cpus);
- exit(EXIT_FAIL_MEM);
- }
- return array;
-}
-
-static struct stats_record *alloc_stats_record(void)
-{
- struct stats_record *rec;
- int i, size;
-
- size = sizeof(*rec) + n_cpus * sizeof(struct record);
- rec = malloc(size);
- if (!rec) {
- fprintf(stderr, "Mem alloc error\n");
- exit(EXIT_FAIL_MEM);
- }
- memset(rec, 0, size);
- rec->rx_cnt.cpu = alloc_record_per_cpu();
- rec->redir_err.cpu = alloc_record_per_cpu();
- rec->kthread.cpu = alloc_record_per_cpu();
- rec->exception.cpu = alloc_record_per_cpu();
- for (i = 0; i < n_cpus; i++)
- rec->enq[i].cpu = alloc_record_per_cpu();
-
- return rec;
-}
-
-static void free_stats_record(struct stats_record *r)
-{
- int i;
-
- for (i = 0; i < n_cpus; i++)
- free(r->enq[i].cpu);
- free(r->exception.cpu);
- free(r->kthread.cpu);
- free(r->redir_err.cpu);
- free(r->rx_cnt.cpu);
- free(r);
-}
-
-static double calc_period(struct record *r, struct record *p)
-{
- double period_ = 0;
- __u64 period = 0;
-
- period = r->timestamp - p->timestamp;
- if (period > 0)
- period_ = ((double) period / NANOSEC_PER_SEC);
-
- return period_;
-}
-
-static __u64 calc_pps(struct datarec *r, struct datarec *p, double period_)
-{
- __u64 packets = 0;
- __u64 pps = 0;
-
- if (period_ > 0) {
- packets = r->processed - p->processed;
- pps = packets / period_;
- }
- return pps;
-}
-
-static __u64 calc_drop_pps(struct datarec *r, struct datarec *p, double period_)
-{
- __u64 packets = 0;
- __u64 pps = 0;
-
- if (period_ > 0) {
- packets = r->dropped - p->dropped;
- pps = packets / period_;
- }
- return pps;
-}
-
-static __u64 calc_errs_pps(struct datarec *r,
- struct datarec *p, double period_)
-{
- __u64 packets = 0;
- __u64 pps = 0;
-
- if (period_ > 0) {
- packets = r->issue - p->issue;
- 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_)
-{
- *xdp_pass = 0, *xdp_drop = 0, *xdp_redirect = 0;
- if (period_ > 0) {
- *xdp_redirect = (r->xdp_redirect - p->xdp_redirect) / period_;
- *xdp_pass = (r->xdp_pass - p->xdp_pass) / period_;
- *xdp_drop = (r->xdp_drop - p->xdp_drop) / period_;
- }
-}
-
-static void stats_print(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- char *prog_name, char *mprog_name, int mprog_fd)
-{
- unsigned int nr_cpus = bpf_num_possible_cpus();
- double pps = 0, drop = 0, err = 0;
- bool mprog_enabled = false;
- struct record *rec, *prev;
- int to_cpu;
- double t;
- int i;
-
- if (mprog_fd > 0)
- mprog_enabled = true;
-
- /* Header */
- printf("Running XDP/eBPF prog_name:%s\n", prog_name);
- printf("%-15s %-7s %-14s %-11s %-9s\n",
- "XDP-cpumap", "CPU:to", "pps", "drop-pps", "extra-info");
-
- /* XDP rx_cnt */
- {
- char *fmt_rx = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
- char *fm2_rx = "%-15s %-7s %'-14.0f %'-11.0f\n";
- char *errstr = "";
-
- rec = &stats_rec->rx_cnt;
- prev = &stats_prev->rx_cnt;
- 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);
- err = calc_errs_pps(r, p, t);
- if (err > 0)
- errstr = "cpu-dest/err";
- if (pps > 0)
- printf(fmt_rx, "XDP-RX",
- i, pps, drop, err, errstr);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- printf(fm2_rx, "XDP-RX", "total", pps, drop);
- }
-
- /* cpumap enqueue stats */
- for (to_cpu = 0; to_cpu < n_cpus; to_cpu++) {
- char *fmt = "%-15s %3d:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
- char *fm2 = "%-15s %3s:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
- char *errstr = "";
-
- rec = &stats_rec->enq[to_cpu];
- prev = &stats_prev->enq[to_cpu];
- 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);
- err = calc_errs_pps(r, p, t);
- if (err > 0) {
- errstr = "bulk-average";
- err = pps / err; /* calc average bulk size */
- }
- if (pps > 0)
- printf(fmt, "cpumap-enqueue",
- i, to_cpu, pps, drop, err, errstr);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- if (pps > 0) {
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- if (err > 0) {
- errstr = "bulk-average";
- err = pps / err; /* calc average bulk size */
- }
- printf(fm2, "cpumap-enqueue",
- "sum", to_cpu, pps, drop, err, errstr);
- }
- }
-
- /* cpumap kthread stats */
- {
- char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
- char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f %s\n";
- char *e_str = "";
-
- rec = &stats_rec->kthread;
- prev = &stats_prev->kthread;
- 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);
- err = calc_errs_pps(r, p, t);
- if (err > 0)
- e_str = "sched";
- if (pps > 0)
- printf(fmt_k, "cpumap_kthread",
- i, pps, drop, err, e_str);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- if (err > 0)
- e_str = "sched-sum";
- printf(fm2_k, "cpumap_kthread", "total", pps, drop, err, e_str);
- }
-
- /* XDP redirect err tracepoints (very unlikely) */
- {
- char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
- char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
-
- rec = &stats_rec->redir_err;
- prev = &stats_prev->redir_err;
- 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);
- if (pps > 0)
- printf(fmt_err, "redirect_err", i, pps, drop);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- printf(fm2_err, "redirect_err", "total", pps, drop);
- }
-
- /* XDP general exception tracepoints */
- {
- char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
- char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
-
- rec = &stats_rec->exception;
- prev = &stats_prev->exception;
- 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);
- if (pps > 0)
- printf(fmt_err, "xdp_exception", i, pps, drop);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- printf(fm2_err, "xdp_exception", "total", pps, drop);
- }
-
- /* CPUMAP attached XDP program that runs on remote/destination CPU */
- if (mprog_enabled) {
- char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f\n";
- char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f\n";
- double xdp_pass, xdp_drop, xdp_redirect;
-
- printf("\n2nd remote XDP/eBPF prog_name: %s\n", mprog_name);
- printf("%-15s %-7s %-14s %-11s %-9s\n",
- "XDP-cpumap", "CPU:to", "xdp-pass", "xdp-drop", "xdp-redir");
-
- rec = &stats_rec->kthread;
- prev = &stats_prev->kthread;
- t = calc_period(rec, prev);
- for (i = 0; i < nr_cpus; i++) {
- struct datarec *r = &rec->cpu[i];
- struct datarec *p = &prev->cpu[i];
-
- calc_xdp_pps(r, p, &xdp_pass, &xdp_drop,
- &xdp_redirect, t);
- if (xdp_pass > 0 || xdp_drop > 0 || xdp_redirect > 0)
- printf(fmt_k, "xdp-in-kthread", i, xdp_pass, xdp_drop,
- xdp_redirect);
- }
- calc_xdp_pps(&rec->total, &prev->total, &xdp_pass, &xdp_drop,
- &xdp_redirect, t);
- printf(fm2_k, "xdp-in-kthread", "total", xdp_pass, xdp_drop, xdp_redirect);
- }
-
- printf("\n");
- fflush(stdout);
-}
-
-static void stats_collect(struct stats_record *rec)
-{
- int fd, i;
-
- fd = map_fds[RX_CNT];
- map_collect_percpu(fd, 0, &rec->rx_cnt);
-
- fd = map_fds[REDIRECT_ERR_CNT];
- map_collect_percpu(fd, 1, &rec->redir_err);
-
- fd = map_fds[CPUMAP_ENQUEUE_CNT];
- for (i = 0; i < n_cpus; i++)
- map_collect_percpu(fd, i, &rec->enq[i]);
-
- fd = map_fds[CPUMAP_KTHREAD_CNT];
- map_collect_percpu(fd, 0, &rec->kthread);
-
- fd = map_fds[EXCEPTION_CNT];
- map_collect_percpu(fd, 0, &rec->exception);
-}
-
-
-/* Pointer swap trick */
-static inline void swap(struct stats_record **a, struct stats_record **b)
-{
- struct stats_record *tmp;
-
- tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value,
__u32 avail_idx, bool new)
{
@@ -579,10 +121,11 @@ static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value,
__u32 key = 0;
int ret;
+ /* Update to bpf_skel */
/* Add a CPU entry to cpumap, as this allocate a cpu entry in
* the kernel for the cpu.
*/
- ret = bpf_map_update_elem(map_fds[CPU_MAP], &cpu, value, 0);
+ ret = bpf_map_update_elem(map_fd, &cpu, value, 0);
if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF);
@@ -591,21 +134,21 @@ static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value,
/* Inform bpf_prog's that a new CPU is available to select
* from via some control maps.
*/
- ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &avail_idx, &cpu, 0);
+ ret = bpf_map_update_elem(avail_fd, &avail_idx, &cpu, 0);
if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF);
}
/* When not replacing/updating existing entry, bump the count */
- ret = bpf_map_lookup_elem(map_fds[CPUS_COUNT], &key, &curr_cpus_count);
+ ret = bpf_map_lookup_elem(count_fd, &key, &curr_cpus_count);
if (ret) {
fprintf(stderr, "Failed reading curr cpus_count\n");
exit(EXIT_FAIL_BPF);
}
if (new) {
curr_cpus_count++;
- ret = bpf_map_update_elem(map_fds[CPUS_COUNT], &key,
+ ret = bpf_map_update_elem(count_fd, &key,
&curr_cpus_count, 0);
if (ret) {
fprintf(stderr, "Failed write curr cpus_count\n");
@@ -629,7 +172,7 @@ static void mark_cpus_unavailable(void)
int ret, i;
for (i = 0; i < n_cpus; i++) {
- ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &i,
+ ret = bpf_map_update_elem(avail_fd, &i,
&invalid_cpu, 0);
if (ret) {
fprintf(stderr, "Failed marking CPU unavailable\n");
@@ -653,26 +196,33 @@ static void stress_cpumap(struct bpf_cpumap_val *value)
create_cpu_entry(1, value, 0, false);
}
-static void stats_poll(int interval, bool use_separators, char *prog_name,
- char *mprog_name, struct bpf_cpumap_val *value,
- bool stress_mode)
+static void __stats_poll(int interval, bool use_separators, char *prog_name,
+ char *mprog_name, struct bpf_cpumap_val *value,
+ bool stress_mode)
{
+ int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
+ SAMPLE_CPUMAP_ENQUEUE_CNT | SAMPLE_CPUMAP_KTHREAD_CNT |
+ SAMPLE_EXCEPTION_CNT;
struct stats_record *record, *prev;
- int mprog_fd;
record = alloc_stats_record();
prev = alloc_stats_record();
- stats_collect(record);
+ sample_stats_collect(mask, record);
/* Trick to pretty printf with thousands separators use %' */
if (use_separators)
setlocale(LC_NUMERIC, "en_US");
- while (1) {
+ for (;;) {
swap(&prev, &record);
- mprog_fd = value->bpf_prog.fd;
- stats_collect(record);
- stats_print(record, prev, prog_name, mprog_name, mprog_fd);
+ sample_stats_collect(mask, record);
+ sample_stats_print(mask, record, prev, prog_name);
+ /* Depends on SAMPLE_CPUMAP_KTHREAD_CNT */
+ sample_stats_print_cpumap_remote(record, prev,
+ bpf_num_possible_cpus(),
+ mprog_name);
+ printf("\n");
+ fflush(stdout);
sleep(interval);
if (stress_mode)
stress_cpumap(value);
@@ -682,41 +232,6 @@ static void stats_poll(int interval, bool use_separators, char *prog_name,
free_stats_record(prev);
}
-static int init_tracepoints(struct bpf_object *obj)
-{
- struct bpf_program *prog;
-
- bpf_object__for_each_program(prog, obj) {
- if (bpf_program__is_tracepoint(prog) != true)
- continue;
-
- tp_links[tp_cnt] = bpf_program__attach(prog);
- if (libbpf_get_error(tp_links[tp_cnt])) {
- tp_links[tp_cnt] = NULL;
- return -EINVAL;
- }
- tp_cnt++;
- }
-
- return 0;
-}
-
-static int init_map_fds(struct bpf_object *obj)
-{
- enum map_type type;
-
- for (type = 0; type < NUM_MAP; type++) {
- map_fds[type] =
- bpf_object__find_map_fd_by_name(obj,
- map_type_strings[type]);
-
- if (map_fds[type] < 0)
- return -ENOENT;
- }
-
- return 0;
-}
-
static int load_cpumap_prog(char *file_name, char *prog_name,
char *redir_interface, char *redir_map)
{
@@ -790,8 +305,6 @@ int main(int argc, char **argv)
int *cpu, i;
__u32 qsize;
- n_cpus = get_nprocs_conf();
-
/* Notice: choosing he queue size is very important with the
* ixgbe driver, because it's driver page recycling trick is
* dependend on pages being returned quickly. The number of
@@ -812,15 +325,20 @@ int main(int argc, char **argv)
return err;
}
- if (init_tracepoints(obj) < 0) {
- fprintf(stderr, "ERR: bpf_program__attach failed\n");
+ if (sample_init(obj) < 0) {
+ fprintf(stderr, "ERR: Failed to initialize sample\n");
return err;
}
- if (init_map_fds(obj) < 0) {
- fprintf(stderr, "bpf_object__find_map_fd_by_name failed\n");
- return err;
+ map_fd = bpf_object__find_map_fd_by_name(obj, "cpu_map");
+ avail_fd = bpf_object__find_map_fd_by_name(obj, "cpus_available");
+ count_fd = bpf_object__find_map_fd_by_name(obj, "cpus_count");
+
+ if (map_fd < 0 || avail_fd < 0 || count_fd < 0) {
+ fprintf(stderr, "failed to find map\n");
+ return EXIT_FAIL;
}
+
mark_cpus_unavailable();
cpu = malloc(n_cpus * sizeof(int));
@@ -967,8 +485,8 @@ int main(int argc, char **argv)
}
prog_id = info.id;
- stats_poll(interval, use_separators, prog_name, mprog_name,
- &value, stress_mode);
+ __stats_poll(interval, use_separators, prog_name, mprog_name,
+ &value, stress_mode);
err = EXIT_OK;
out:
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
new file mode 100644
index 000000000000..be60fbddd8c7
--- /dev/null
+++ b/samples/bpf/xdp_sample_user.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/resource.h>
+#include <sys/sysinfo.h>
+#include <getopt.h>
+#include <net/if.h>
+#include <time.h>
+#include <linux/limits.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#ifndef SIOCETHTOOL
+#define SIOCETHTOOL 0x8946
+#endif
+
+#include <arpa/inet.h>
+#include <linux/if_link.h>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+#include "bpf_util.h"
+#include "xdp_sample_user.h"
+
+struct bpf_link *tp_links[NUM_TP] = {};
+int map_fds[NUM_MAP], tp_cnt, n_cpus;
+
+#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
+static __u64 gettime(void)
+{
+ struct timespec t;
+ int res;
+
+ res = clock_gettime(CLOCK_MONOTONIC, &t);
+ if (res < 0) {
+ fprintf(stderr, "Error with gettimeofday! (%i)\n", res);
+ exit(EXIT_FAIL);
+ }
+ return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
+}
+
+static bool map_collect_percpu(int fd, __u32 key, struct record *rec)
+{
+ /* For percpu maps, userspace gets a value per possible CPU */
+ unsigned int nr_cpus = bpf_num_possible_cpus();
+ struct datarec values[nr_cpus];
+ __u64 sum_xdp_redirect = 0;
+ __u64 sum_xdp_pass = 0;
+ __u64 sum_xdp_drop = 0;
+ __u64 sum_processed = 0;
+ __u64 sum_dropped = 0;
+ __u64 sum_issue = 0;
+ int i;
+
+ if ((bpf_map_lookup_elem(fd, &key, values)) != 0) {
+ fprintf(stderr,
+ "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
+ return false;
+ }
+ /* Get time as close as possible to reading map contents */
+ rec->timestamp = gettime();
+
+ /* Record and sum values from each CPU */
+ for (i = 0; i < nr_cpus; i++) {
+ rec->cpu[i].processed = values[i].processed;
+ sum_processed += values[i].processed;
+ rec->cpu[i].dropped = values[i].dropped;
+ sum_dropped += values[i].dropped;
+ rec->cpu[i].issue = values[i].issue;
+ sum_issue += values[i].issue;
+ rec->cpu[i].xdp_pass = values[i].xdp_pass;
+ sum_xdp_pass += values[i].xdp_pass;
+ rec->cpu[i].xdp_drop = values[i].xdp_drop;
+ sum_xdp_drop += values[i].xdp_drop;
+ rec->cpu[i].xdp_redirect = values[i].xdp_redirect;
+ sum_xdp_redirect += values[i].xdp_redirect;
+ }
+ rec->total.processed = sum_processed;
+ rec->total.dropped = sum_dropped;
+ rec->total.issue = sum_issue;
+ rec->total.xdp_pass = sum_xdp_pass;
+ rec->total.xdp_drop = sum_xdp_drop;
+ rec->total.xdp_redirect = sum_xdp_redirect;
+ return true;
+}
+
+static struct datarec *alloc_record_per_cpu(void)
+{
+ unsigned int nr_cpus = bpf_num_possible_cpus();
+ struct datarec *array;
+
+ array = calloc(nr_cpus, sizeof(struct datarec));
+ if (!array) {
+ fprintf(stderr, "Mem alloc error (nr_cpus:%u)\n", nr_cpus);
+ exit(EXIT_FAIL_MEM);
+ }
+ return array;
+}
+
+struct stats_record *alloc_stats_record(void)
+{
+ struct stats_record *rec;
+ int i, size;
+
+ size = sizeof(*rec) + n_cpus * sizeof(struct record);
+ rec = malloc(size);
+ if (!rec) {
+ fprintf(stderr, "Mem alloc error\n");
+ exit(EXIT_FAIL_MEM);
+ }
+ memset(rec, 0, size);
+ rec->rx_cnt.cpu = alloc_record_per_cpu();
+ rec->redir_err.cpu = alloc_record_per_cpu();
+ rec->kthread.cpu = alloc_record_per_cpu();
+ rec->exception.cpu = alloc_record_per_cpu();
+ for (i = 0; i < n_cpus; i++)
+ rec->enq[i].cpu = alloc_record_per_cpu();
+
+ return rec;
+}
+
+void free_stats_record(struct stats_record *r)
+{
+ int i;
+
+ for (i = 0; i < n_cpus; i++)
+ free(r->enq[i].cpu);
+ free(r->exception.cpu);
+ free(r->kthread.cpu);
+ free(r->redir_err.cpu);
+ free(r->rx_cnt.cpu);
+ free(r);
+}
+
+static double calc_period(struct record *r, struct record *p)
+{
+ double period_ = 0;
+ __u64 period = 0;
+
+ period = r->timestamp - p->timestamp;
+ if (period > 0)
+ period_ = ((double) period / NANOSEC_PER_SEC);
+
+ return period_;
+}
+
+static __u64 calc_pps(struct datarec *r, struct datarec *p, double period_)
+{
+ __u64 packets = 0;
+ __u64 pps = 0;
+
+ if (period_ > 0) {
+ packets = r->processed - p->processed;
+ pps = packets / period_;
+ }
+ return pps;
+}
+
+static __u64 calc_drop_pps(struct datarec *r, struct datarec *p, double period_)
+{
+ __u64 packets = 0;
+ __u64 pps = 0;
+
+ if (period_ > 0) {
+ packets = r->dropped - p->dropped;
+ pps = packets / period_;
+ }
+ return pps;
+}
+
+static __u64 calc_errs_pps(struct datarec *r,
+ struct datarec *p, double period_)
+{
+ __u64 packets = 0;
+ __u64 pps = 0;
+
+ if (period_ > 0) {
+ packets = r->issue - p->issue;
+ 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_)
+{
+ *xdp_pass = 0, *xdp_drop = 0, *xdp_redirect = 0;
+ if (period_ > 0) {
+ *xdp_redirect = (r->xdp_redirect - p->xdp_redirect) / period_;
+ *xdp_pass = (r->xdp_pass - p->xdp_pass) / period_;
+ *xdp_drop = (r->xdp_drop - p->xdp_drop) / period_;
+ }
+}
+
+static void stats_print_rx_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ char *fmt_rx = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
+ char *fm2_rx = "%-15s %-7s %'-14.0f %'-11.0f\n";
+ struct record *rec, *prev;
+ double t, pps, drop, err;
+ char *errstr = "";
+ int i;
+
+ rec = &stats_rec->rx_cnt;
+ prev = &stats_prev->rx_cnt;
+ 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);
+ err = calc_errs_pps(r, p, t);
+ if (err > 0)
+ errstr = "cpu-dest/err";
+ if (pps > 0)
+ printf(fmt_rx, "XDP-RX", i, pps, drop, err, errstr);
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+ printf(fm2_rx, "XDP-RX", "total", pps, drop);
+}
+
+static void stats_print_cpumap_enqueue(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ struct record *rec, *prev;
+ double t, pps, drop, err;
+ int i, to_cpu;
+
+ /* cpumap enqueue stats */
+ for (to_cpu = 0; to_cpu < n_cpus; to_cpu++) {
+ char *fmt = "%-15s %3d:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
+ char *fm2 = "%-15s %3s:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
+ char *errstr = "";
+
+ rec = &stats_rec->enq[to_cpu];
+ prev = &stats_prev->enq[to_cpu];
+ 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);
+ err = calc_errs_pps(r, p, t);
+ if (err > 0) {
+ errstr = "bulk-average";
+ err = pps / err; /* calc average bulk size */
+ }
+ if (pps > 0)
+ printf(fmt, "cpumap-enqueue",
+ i, to_cpu, pps, drop, err, errstr);
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ if (pps > 0) {
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+ if (err > 0) {
+ errstr = "bulk-average";
+ err = pps / err; /* calc average bulk size */
+ }
+ printf(fm2, "cpumap-enqueue",
+ "sum", to_cpu, pps, drop, err, errstr);
+ }
+ }
+}
+
+static void stats_print_cpumap_kthread(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
+ char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f %s\n";
+ struct record *rec, *prev;
+ double t, pps, drop, err;
+ char *e_str = "";
+ int i;
+
+ rec = &stats_rec->kthread;
+ prev = &stats_prev->kthread;
+ 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);
+ err = calc_errs_pps(r, p, t);
+ if (err > 0)
+ e_str = "sched";
+ if (pps > 0)
+ printf(fmt_k, "cpumap_kthread", i, pps, drop, err,
+ e_str);
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+ if (err > 0)
+ e_str = "sched-sum";
+ printf(fm2_k, "cpumap_kthread", "total", pps, drop, err, e_str);
+}
+
+static void stats_print_redirect_err_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
+ char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
+ struct record *rec, *prev;
+ double t, pps, drop;
+ int i;
+
+ rec = &stats_rec->redir_err;
+ prev = &stats_prev->redir_err;
+ 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);
+ if (pps > 0)
+ printf(fmt_err, "redirect_err", i, pps, drop);
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ printf(fm2_err, "redirect_err", "total", pps, drop);
+}
+
+static void stats_print_exception_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
+ char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
+ struct record *rec, *prev;
+ double t, pps, drop;
+ int i;
+
+ rec = &stats_rec->exception;
+ prev = &stats_prev->exception;
+ 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);
+ if (pps > 0)
+ printf(fmt_err, "xdp_exception", i, pps, drop);
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ printf(fm2_err, "xdp_exception", "total", pps, drop);
+}
+
+void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, char *mprog_name)
+{
+ char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f\n";
+ char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f\n";
+ double xdp_pass, xdp_drop, xdp_redirect;
+ struct record *rec, *prev;
+ double t;
+ int i;
+
+ printf("\n2nd remote XDP/eBPF prog_name: %s\n", mprog_name ?: "(none)");
+ printf("%-15s %-7s %-14s %-11s %-9s\n", "XDP-cpumap", "CPU:to",
+ "xdp-pass", "xdp-drop", "xdp-redir");
+
+ rec = &stats_rec->kthread;
+ prev = &stats_prev->kthread;
+ t = calc_period(rec, prev);
+ for (i = 0; i < nr_cpus; i++) {
+ struct datarec *r = &rec->cpu[i];
+ struct datarec *p = &prev->cpu[i];
+
+ calc_xdp_pps(r, p, &xdp_pass, &xdp_drop, &xdp_redirect, t);
+ if (xdp_pass > 0 || xdp_drop > 0 || xdp_redirect > 0)
+ printf(fmt_k, "xdp-in-kthread", i, xdp_pass, xdp_drop,
+ xdp_redirect);
+ }
+ calc_xdp_pps(&rec->total, &prev->total, &xdp_pass, &xdp_drop,
+ &xdp_redirect, t);
+ printf(fm2_k, "xdp-in-kthread", "total", xdp_pass, xdp_drop,
+ xdp_redirect);
+}
+
+static int init_tracepoints(struct bpf_object *obj)
+{
+ struct bpf_program *prog;
+
+ bpf_object__for_each_program(prog, obj) {
+ if (bpf_program__is_tracepoint(prog) != true)
+ continue;
+
+ tp_links[tp_cnt] = bpf_program__attach(prog);
+ if (libbpf_get_error(tp_links[tp_cnt])) {
+ tp_links[tp_cnt] = NULL;
+ return -EINVAL;
+ }
+ tp_cnt++;
+ }
+
+ return 0;
+}
+
+static int init_map_fds(struct bpf_object *obj)
+{
+ enum map_type type;
+
+ for (type = 0; type < NUM_MAP; type++) {
+ map_fds[type] =
+ bpf_object__find_map_fd_by_name(obj,
+ map_type_strings[type]);
+
+ if (map_fds[type] < 0)
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+int sample_init(struct bpf_object *obj)
+{
+ n_cpus = get_nprocs_conf();
+ return init_tracepoints(obj) ? : init_map_fds(obj);
+}
+
+void sample_exit(int status)
+{
+ while (tp_cnt)
+ bpf_link__destroy(tp_links[--tp_cnt]);
+
+ exit(status);
+}
+
+void sample_stats_collect(int mask, struct stats_record *rec)
+{
+ int i;
+
+ if (mask & SAMPLE_RX_CNT)
+ map_collect_percpu(map_fds[RX_CNT], 0, &rec->rx_cnt);
+
+ if (mask & SAMPLE_REDIRECT_ERR_CNT)
+ map_collect_percpu(map_fds[REDIRECT_ERR_CNT], 1, &rec->redir_err);
+
+ if (mask & SAMPLE_CPUMAP_ENQUEUE_CNT)
+ for (i = 0; i < n_cpus; i++)
+ map_collect_percpu(map_fds[CPUMAP_ENQUEUE_CNT], i, &rec->enq[i]);
+
+ if (mask & SAMPLE_CPUMAP_KTHREAD_CNT)
+ map_collect_percpu(map_fds[CPUMAP_KTHREAD_CNT], 0, &rec->kthread);
+
+ if (mask & SAMPLE_EXCEPTION_CNT)
+ map_collect_percpu(map_fds[EXCEPTION_CNT], 0, &rec->exception);
+}
+
+void sample_stats_print(int mask, struct stats_record *cur,
+ struct stats_record *prev, char *prog_name)
+{
+ int nr_cpus = bpf_num_possible_cpus();
+
+ printf("Running XDP/eBPF prog_name:%s\n", prog_name ?: "(none)");
+ printf("%-15s %-7s %-14s %-11s %-9s\n",
+ "XDP-event", "CPU:to", "pps", "drop-pps", "extra-info");
+
+ if (mask & SAMPLE_RX_CNT)
+ stats_print_rx_cnt(cur, prev, nr_cpus);
+
+ if (mask & SAMPLE_REDIRECT_ERR_CNT)
+ stats_print_redirect_err_cnt(cur, prev, nr_cpus);
+
+ if (mask & SAMPLE_CPUMAP_ENQUEUE_CNT)
+ stats_print_cpumap_enqueue(cur, prev, nr_cpus);
+
+ if (mask & SAMPLE_CPUMAP_KTHREAD_CNT)
+ stats_print_cpumap_kthread(cur, prev, nr_cpus);
+
+ if (mask & SAMPLE_EXCEPTION_CNT)
+ stats_print_exception_cnt(cur, prev, nr_cpus);
+}
+
+void sample_stats_poll(int interval, int mask, char *prog_name, int use_separators)
+{
+ struct stats_record *record, *prev;
+
+ record = alloc_stats_record();
+ prev = alloc_stats_record();
+ sample_stats_collect(mask, record);
+
+ /* Trick to pretty printf with thousands separators use %' */
+ if (use_separators)
+ setlocale(LC_NUMERIC, "en_US");
+
+ for (;;) {
+ swap(&prev, &record);
+ sample_stats_collect(mask, record);
+ sample_stats_print(mask, record, prev, NULL);
+ printf("\n");
+ fflush(stdout);
+ sleep(interval);
+ }
+
+ free_stats_record(record);
+ free_stats_record(prev);
+}
+
+const char *get_driver_name(int ifindex)
+{
+ struct ethtool_drvinfo drv = {};
+ char ifname[IF_NAMESIZE];
+ static char drvname[32];
+ struct ifreq ifr = {};
+ int fd, r;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return NULL;
+
+ if (!if_indextoname(ifindex, ifname))
+ goto end;
+
+ drv.cmd = ETHTOOL_GDRVINFO;
+ strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
+ ifr.ifr_data = (void *)&drv;
+
+ r = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (r)
+ goto end;
+
+ strncpy(drvname, drv.driver, sizeof(drvname));
+
+ close(fd);
+ return drvname;
+
+end:
+ close(fd);
+ return NULL;
+}
+
+int get_mac_addr(int ifindex, void *mac_addr)
+{
+ char ifname[IF_NAMESIZE];
+ struct ifreq ifr = {};
+ int fd, r;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -errno;
+
+ if (!if_indextoname(ifindex, ifname)) {
+ r = -errno;
+ goto end;
+ }
+
+ strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
+
+ r = ioctl(fd, SIOCGIFHWADDR, &ifr);
+ if (r) {
+ r = -errno;
+ goto end;
+ }
+
+ memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6 * sizeof(char));
+
+end:
+ close(fd);
+ return r;
+}
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
new file mode 100644
index 000000000000..3427baf70fc0
--- /dev/null
+++ b/samples/bpf/xdp_sample_user.h
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#pragma once
+
+#include <bpf/libbpf.h>
+
+enum map_type {
+ RX_CNT,
+ REDIRECT_ERR_CNT,
+ CPUMAP_ENQUEUE_CNT,
+ CPUMAP_KTHREAD_CNT,
+ EXCEPTION_CNT,
+ NUM_MAP,
+};
+
+enum tp_type {
+ TP_REDIRECT_ERR_CNT,
+ TP_REDIRECT_MAP_ERR_CNT,
+ TP_CPUMAP_ENQUEUE_CNT,
+ TP_CPUMAP_KTHREAD_CNT,
+ TP_EXCEPTION_CNT,
+ NUM_TP,
+};
+
+enum stats_mask {
+ SAMPLE_RX_CNT = 1U << 1,
+ SAMPLE_REDIRECT_ERR_CNT = 1U << 2,
+ SAMPLE_CPUMAP_ENQUEUE_CNT = 1U << 3,
+ SAMPLE_CPUMAP_KTHREAD_CNT = 1U << 4,
+ SAMPLE_EXCEPTION_CNT = 1U << 5,
+};
+
+static const char *const map_type_strings[] = {
+ [RX_CNT] = "rx_cnt",
+ [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+ [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+ [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+ [EXCEPTION_CNT] = "exception_cnt",
+};
+
+extern struct bpf_link *tp_links[NUM_TP];
+extern int map_fds[NUM_MAP];
+extern int n_cpus;
+extern int tp_cnt;
+
+/* Exit return codes */
+#define EXIT_OK 0
+#define EXIT_FAIL 1
+#define EXIT_FAIL_OPTION 2
+#define EXIT_FAIL_XDP 3
+#define EXIT_FAIL_BPF 4
+#define EXIT_FAIL_MEM 5
+
+/* Common stats data record shared with _kern.c */
+struct datarec {
+ __u64 processed;
+ __u64 dropped;
+ __u64 issue;
+ __u64 xdp_pass;
+ __u64 xdp_drop;
+ __u64 xdp_redirect;
+};
+
+struct record {
+ __u64 timestamp;
+ struct datarec total;
+ struct datarec *cpu;
+};
+
+struct stats_record {
+ struct record rx_cnt;
+ struct record redir_err;
+ struct record kthread;
+ struct record exception;
+ struct record enq[];
+};
+
+int sample_init(struct bpf_object *obj);
+void sample_exit(int status);
+struct stats_record *alloc_stats_record(void);
+void free_stats_record(struct stats_record *rec);
+void sample_stats_print(int mask, struct stats_record *cur,
+ struct stats_record *prev, char *prog_name);
+void sample_stats_collect(int mask, struct stats_record *rec);
+void sample_stats_poll(int interval, int mask, char *prog_name,
+ int use_separators);
+void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, char *mprog_name);
+
+const char *get_driver_name(int ifindex);
+int get_mac_addr(int ifindex, void *mac_addr);
+
+/* Pointer swap trick */
+static inline void swap(struct stats_record **a, struct stats_record **b)
+{
+ struct stats_record *tmp;
+
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 05/15] samples: bpf: convert xdp_redirect_map to use xdp_samples
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (3 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 04/15] samples: bpf: refactor generic parts out of xdp_redirect_cpu_user Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 06/15] samples: bpf: prepare devmap_xmit support in xdp_sample Kumar Kartikeya Dwivedi
` (9 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This uses the xdp_sample_* reorg we did in the past commits to report
more statistics than just the per second packet count.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/Makefile | 2 +-
samples/bpf/xdp_redirect_map_kern.c | 23 +++----
samples/bpf/xdp_redirect_map_user.c | 96 +++++++++++------------------
3 files changed, 44 insertions(+), 77 deletions(-)
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index c0c02e12e28b..ea7100c8b760 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -99,8 +99,8 @@ xdp_tx_iptunnel-objs := xdp_tx_iptunnel_user.o
test_map_in_map-objs := test_map_in_map_user.o
per_socket_stats_example-objs := cookie_uid_helper_example.o
xdp_redirect-objs := xdp_redirect_user.o
-xdp_redirect_map-objs := xdp_redirect_map_user.o
xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o
+xdp_redirect_map-objs := xdp_redirect_map_user.o xdp_sample_user.o
xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_sample_user.o
xdp_monitor-objs := xdp_monitor_user.o
xdp_rxq_info-objs := xdp_rxq_info_user.o
diff --git a/samples/bpf/xdp_redirect_map_kern.c b/samples/bpf/xdp_redirect_map_kern.c
index a92b8e567bdd..cf8b8f6d15da 100644
--- a/samples/bpf/xdp_redirect_map_kern.c
+++ b/samples/bpf/xdp_redirect_map_kern.c
@@ -19,6 +19,8 @@
#include <linux/ipv6.h>
#include <bpf/bpf_helpers.h>
+#include "xdp_sample_kern.h"
+
/* The 2nd xdp prog on egress does not support skb mode, so we define two
* maps, tx_port_general and tx_port_native.
*/
@@ -36,16 +38,6 @@ struct {
__uint(max_entries, 100);
} tx_port_native SEC(".maps");
-/* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
- * feedback. Redirect TX errors can be caught via a tracepoint.
- */
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, long);
- __uint(max_entries, 1);
-} rxcnt SEC(".maps");
-
/* map to store egress interface mac address */
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
@@ -75,7 +67,7 @@ static __always_inline int xdp_redirect_map(struct xdp_md *ctx, void *redirect_m
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
- int rc = XDP_DROP;
+ struct datarec *rec;
long *value;
u32 key = 0;
u64 nh_off;
@@ -83,15 +75,16 @@ static __always_inline int xdp_redirect_map(struct xdp_md *ctx, void *redirect_m
nh_off = sizeof(*eth);
if (data + nh_off > data_end)
- return rc;
+ return XDP_DROP;
/* constant virtual port */
vport = 0;
/* count packet in global counter */
- value = bpf_map_lookup_elem(&rxcnt, &key);
- if (value)
- *value += 1;
+ rec = bpf_map_lookup_elem(&rx_cnt, &key);
+ if (!rec)
+ return XDP_ABORTED;
+ rec->processed++;
swap_src_dst_mac(data);
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index ad3cdc4c07d3..42893385ba96 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -13,15 +13,11 @@
#include <net/if.h>
#include <unistd.h>
#include <libgen.h>
-#include <sys/resource.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include "bpf_util.h"
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
+#include "xdp_sample_user.h"
static int ifindex_in;
static int ifindex_out;
@@ -31,7 +27,6 @@ static __u32 prog_id;
static __u32 dummy_prog_id;
static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
-static int rxcnt_map_fd;
static void int_exit(int sig)
{
@@ -62,56 +57,8 @@ static void int_exit(int sig)
else
printf("program on iface OUT changed, not removing\n");
}
- exit(0);
-}
-static void poll_stats(int interval, int ifindex)
-{
- unsigned int nr_cpus = bpf_num_possible_cpus();
- __u64 values[nr_cpus], prev[nr_cpus];
-
- memset(prev, 0, sizeof(prev));
-
- while (1) {
- __u64 sum = 0;
- __u32 key = 0;
- int i;
-
- sleep(interval);
- assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0);
- for (i = 0; i < nr_cpus; i++)
- sum += (values[i] - prev[i]);
- if (sum)
- printf("ifindex %i: %10llu pkt/s\n",
- ifindex, sum / interval);
- memcpy(prev, values, sizeof(values));
- }
-}
-
-static int get_mac_addr(unsigned int ifindex_out, void *mac_addr)
-{
- char ifname[IF_NAMESIZE];
- struct ifreq ifr;
- int fd, ret = -1;
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd < 0)
- return ret;
-
- if (!if_indextoname(ifindex_out, ifname))
- goto err_out;
-
- strcpy(ifr.ifr_name, ifname);
-
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
- goto err_out;
-
- memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6 * sizeof(char));
- ret = 0;
-
-err_out:
- close(fd);
- return ret;
+ sample_exit(EXIT_OK);
}
static void usage(const char *prog)
@@ -128,6 +75,8 @@ static void usage(const char *prog)
int main(int argc, char **argv)
{
+ int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
+ SAMPLE_EXCEPTION_CNT;
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
};
@@ -136,8 +85,11 @@ int main(int argc, char **argv)
int tx_port_map_fd, tx_mac_map_fd;
struct bpf_devmap_val devmap_val;
struct bpf_prog_info info = {};
+ char str[2 * IF_NAMESIZE + 1];
__u32 info_len = sizeof(info);
+ char ifname_out[IF_NAMESIZE];
const char *optstr = "FSNX";
+ char ifname_in[IF_NAMESIZE];
struct bpf_object *obj;
int ret, opt, key = 0;
char filename[256];
@@ -182,14 +134,17 @@ int main(int argc, char **argv)
if (!ifindex_out)
ifindex_out = strtoul(argv[optind + 1], NULL, 0);
- printf("input: %d output: %d\n", ifindex_in, ifindex_out);
-
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
+ if (sample_init(obj) < 0) {
+ fprintf(stderr, "Failed to initialize sample\n");
+ return 1;
+ }
+
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");
@@ -210,8 +165,7 @@ int main(int argc, char **argv)
}
tx_mac_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_mac");
- rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
- if (tx_mac_map_fd < 0 || rxcnt_map_fd < 0) {
+ if (tx_mac_map_fd < 0) {
printf("bpf_object__find_map_fd_by_name failed\n");
return 1;
}
@@ -281,8 +235,28 @@ int main(int argc, char **argv)
goto out;
}
- poll_stats(2, ifindex_out);
+ if (!if_indextoname(ifindex_in, ifname_in)) {
+ perror("if_nametoindex");
+ goto out;
+ }
+
+ if (!if_indextoname(ifindex_out, ifname_out)) {
+ perror("if_nametoindex");
+ goto out;
+ }
+
+ strncpy(str, get_driver_name(ifindex_in) ?: "(err)", sizeof(str));
+
+ printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n",
+ ifname_in, ifindex_in, str, ifname_out, ifindex_out,
+ get_driver_name(ifindex_out) ?: "(err)");
+
+ snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
+
+ sample_stats_poll(1, mask, str, true);
-out:
return 0;
+
+out:
+ return 1;
}
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 06/15] samples: bpf: prepare devmap_xmit support in xdp_sample
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (4 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 05/15] samples: bpf: convert xdp_redirect_map to use xdp_samples Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 07/15] samples: bpf: add extended reporting for xdp redirect error Kumar Kartikeya Dwivedi
` (8 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This will be used to convert xdp_monitor to xdp_sample reorg in the next
patch.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 07/15] samples: bpf: add extended reporting for xdp redirect error
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (5 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 06/15] samples: bpf: prepare devmap_xmit support in xdp_sample Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 08/15] samples: bpf: add per exception reporting for xdp_exception Kumar Kartikeya Dwivedi
` (7 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This again is needed for xdp_monitor support. We also record the most
common errnos, but don't report for now. A future commit that modifies
output format will arrange for printing it properly.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_sample_kern.h | 53 +++++++++++++++++++++++++++---
samples/bpf/xdp_sample_user.c | 62 +++++++++++++++++++++++++++--------
samples/bpf/xdp_sample_user.h | 13 +++++++-
3 files changed, 108 insertions(+), 20 deletions(-)
diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
index 3b85d71434d3..4131b9cb1ec4 100644
--- a/samples/bpf/xdp_sample_kern.h
+++ b/samples/bpf/xdp_sample_kern.h
@@ -7,6 +7,11 @@
#define MAX_CPUS 64
+#define EINVAL 22
+#define ENETDOWN 100
+#define EMSGSIZE 90
+#define EOPNOTSUPP 95
+
/* Common stats data record to keep userspace more simple */
struct datarec {
__u64 processed;
@@ -35,8 +40,11 @@ struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, u32);
__type(value, struct datarec);
- __uint(max_entries, 2);
- /* TODO: have entries for all possible errno's */
+ __uint(max_entries, 2
+ + 1 /* EINVAL */
+ + 1 /* ENETDOWN */
+ + 1 /* EMSGSIZE */
+ + 1 /* EOPNOTSUPP */);
} redirect_err_cnt SEC(".maps");
/* Used by trace point */
@@ -91,6 +99,25 @@ enum {
XDP_REDIRECT_ERROR = 1
};
+static __always_inline
+__u32 xdp_get_err_key(int err)
+{
+ switch (err) {
+ case 0:
+ return 0;
+ case -EINVAL:
+ return 2;
+ case -ENETDOWN:
+ return 3;
+ case -EMSGSIZE:
+ return 4;
+ case -EOPNOTSUPP:
+ return 5;
+ default:
+ return 1;
+ }
+}
+
static __always_inline
int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
{
@@ -98,13 +125,15 @@ int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
struct datarec *rec;
int err = ctx->err;
- if (!err)
- key = XDP_REDIRECT_SUCCESS;
+ key = xdp_get_err_key(err);
rec = bpf_map_lookup_elem(&redirect_err_cnt, &key);
if (!rec)
return 0;
- rec->dropped += 1;
+ if (key)
+ rec->dropped++;
+ else
+ rec->processed++;
return 0; /* Indicate event was filtered (no further processing)*/
/*
@@ -127,6 +156,20 @@ int trace_xdp_redirect_map_err(struct xdp_redirect_ctx *ctx)
return xdp_redirect_collect_stat(ctx);
}
+/* Likely unloaded when prog starts */
+SEC("tracepoint/xdp/xdp_redirect")
+int trace_xdp_redirect(struct xdp_redirect_ctx *ctx)
+{
+ return xdp_redirect_collect_stat(ctx);
+}
+
+/* Likely unloaded when prog starts */
+SEC("tracepoint/xdp/xdp_redirect_map")
+int trace_xdp_redirect_map(struct xdp_redirect_ctx *ctx)
+{
+ return xdp_redirect_collect_stat(ctx);
+}
+
/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
* Code in: kernel/include/trace/events/xdp.h
*/
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index 56cd79ba303a..29410d551574 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -121,7 +121,8 @@ struct stats_record *alloc_stats_record(void)
}
memset(rec, 0, size);
rec->rx_cnt.cpu = alloc_record_per_cpu();
- rec->redir_err.cpu = alloc_record_per_cpu();
+ rec->redir_err[0].cpu = alloc_record_per_cpu();
+ rec->redir_err[1].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();
@@ -140,7 +141,8 @@ void free_stats_record(struct stats_record *r)
free(r->devmap_xmit.cpu);
free(r->exception.cpu);
free(r->kthread.cpu);
- free(r->redir_err.cpu);
+ free(r->redir_err[1].cpu);
+ free(r->redir_err[0].cpu);
free(r->rx_cnt.cpu);
free(r);
}
@@ -332,31 +334,54 @@ static void stats_print_cpumap_kthread(struct stats_record *stats_rec,
printf(fm2_k, "cpumap_kthread", "total", pps, drop, err, e_str);
}
+static void stats_print_redirect_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
+{
+ char *fmt1 = "%-15s %-7d %'-14.0f %'-11.0f %s\n";
+ char *fmt2 = "%-15s %-7s %'-14.0f %'-11.0f %s\n";
+ struct record *rec, *prev;
+ double t, pps;
+ int i;
+
+ rec = &stats_rec->redir_err[0];
+ prev = &stats_prev->redir_err[0];
+ 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);
+ if (pps > 0)
+ printf(fmt1, "redirect", i, pps, 0.0, "Success");
+ }
+ pps = calc_pps(&rec->total, &prev->total, t);
+ printf(fmt2, "redirect", "total", pps, 0.0, "Success");
+}
+
static void stats_print_redirect_err_cnt(struct stats_record *stats_rec,
struct stats_record *stats_prev,
unsigned int nr_cpus)
{
- char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
- char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
+ char *fmt1 = "%-15s %-7d %'-14.0f %'-11.0f %s\n";
+ char *fmt2 = "%-15s %-7s %'-14.0f %'-11.0f %s\n";
struct record *rec, *prev;
- double t, pps, drop;
+ double t, drop;
int i;
- rec = &stats_rec->redir_err;
- prev = &stats_prev->redir_err;
+ rec = &stats_rec->redir_err[1];
+ prev = &stats_prev->redir_err[1];
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);
- if (pps > 0)
- printf(fmt_err, "redirect_err", i, pps, drop);
+ if (drop > 0)
+ printf(fmt1, "redirect", i, 0.0, drop, "Error");
}
- pps = calc_pps(&rec->total, &prev->total, t);
drop = calc_drop_pps(&rec->total, &prev->total, t);
- printf(fm2_err, "redirect_err", "total", pps, drop);
+ printf(fmt2, "redirect", "total", 0.0, drop, "Error");
}
static void stats_print_exception_cnt(struct stats_record *stats_rec,
@@ -522,8 +547,14 @@ void sample_stats_collect(int mask, struct stats_record *rec)
if (mask & SAMPLE_RX_CNT)
map_collect_percpu(map_fds[RX_CNT], 0, &rec->rx_cnt);
- if (mask & SAMPLE_REDIRECT_ERR_CNT)
- map_collect_percpu(map_fds[REDIRECT_ERR_CNT], 1, &rec->redir_err);
+ /* Success case */
+ if (mask & SAMPLE_REDIRECT_CNT)
+ map_collect_percpu(map_fds[REDIRECT_ERR_CNT], 0, &rec->redir_err[0]);
+
+ if (mask & SAMPLE_REDIRECT_ERR_CNT) {
+ for (i = 1; i < XDP_REDIRECT_ERR_MAX; i++)
+ map_collect_percpu(map_fds[REDIRECT_ERR_CNT], i, &rec->redir_err[i]);
+ }
if (mask & SAMPLE_CPUMAP_ENQUEUE_CNT)
for (i = 0; i < n_cpus; i++)
@@ -551,6 +582,9 @@ void sample_stats_print(int mask, struct stats_record *cur,
if (mask & SAMPLE_RX_CNT)
stats_print_rx_cnt(cur, prev, nr_cpus);
+ if (mask & SAMPLE_REDIRECT_CNT)
+ stats_print_redirect_cnt(cur, prev, nr_cpus);
+
if (mask & SAMPLE_REDIRECT_ERR_CNT)
stats_print_redirect_err_cnt(cur, prev, nr_cpus);
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index 75a4ea4b55ad..a3a3c746e73e 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -14,6 +14,8 @@ enum map_type {
};
enum tp_type {
+ TP_REDIRECT_CNT,
+ TP_REDIRECT_MAP_CNT,
TP_REDIRECT_ERR_CNT,
TP_REDIRECT_MAP_ERR_CNT,
TP_CPUMAP_ENQUEUE_CNT,
@@ -30,6 +32,7 @@ enum stats_mask {
SAMPLE_CPUMAP_KTHREAD_CNT = 1U << 4,
SAMPLE_EXCEPTION_CNT = 1U << 5,
SAMPLE_DEVMAP_XMIT_CNT = 1U << 6,
+ SAMPLE_REDIRECT_CNT = 1U << 7,
};
static const char *const map_type_strings[] = {
@@ -54,6 +57,14 @@ extern int tp_cnt;
#define EXIT_FAIL_BPF 4
#define EXIT_FAIL_MEM 5
+#define XDP_REDIRECT_ERR_MAX 6
+
+static const char *xdp_redirect_err_names[XDP_REDIRECT_ERR_MAX] = {
+ /* Key=1 keeps unknown errors */
+ "Success", "Unknown", "EINVAL", "ENETDOWN", "EMSGSIZE",
+ "EOPNOTSUPP",
+};
+
/* Common stats data record shared with _kern.c */
struct datarec {
__u64 processed;
@@ -75,7 +86,7 @@ struct record {
struct stats_record {
struct record rx_cnt;
- struct record redir_err;
+ struct record redir_err[XDP_REDIRECT_ERR_MAX];
struct record kthread;
struct record exception;
struct record devmap_xmit;
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 08/15] samples: bpf: add per exception reporting for xdp_exception
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (6 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 07/15] samples: bpf: add extended reporting for xdp redirect error Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 09/15] samples: bpf: convert xdp_monitor to use xdp_samples Kumar Kartikeya Dwivedi
` (6 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This is taken from xdp_monitor, in preparation for the conversion in a
subsequent patch.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_sample_kern.h | 8 ++++--
samples/bpf/xdp_sample_user.c | 47 ++++++++++++++++++++---------------
samples/bpf/xdp_sample_user.h | 24 ++++++++++++++++--
3 files changed, 55 insertions(+), 24 deletions(-)
diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
index 4131b9cb1ec4..ec36e7b4a3ba 100644
--- a/samples/bpf/xdp_sample_kern.h
+++ b/samples/bpf/xdp_sample_kern.h
@@ -63,12 +63,13 @@ struct {
__uint(max_entries, 1);
} cpumap_kthread_cnt SEC(".maps");
+#define XDP_UNKNOWN (XDP_REDIRECT + 1)
/* Used by trace point */
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, u32);
__type(value, struct datarec);
- __uint(max_entries, 1);
+ __uint(max_entries, XDP_UNKNOWN + 1);
} exception_cnt SEC(".maps");
struct {
@@ -184,7 +185,10 @@ SEC("tracepoint/xdp/xdp_exception")
int trace_xdp_exception(struct xdp_exception_ctx *ctx)
{
struct datarec *rec;
- u32 key = 0;
+ u32 key = ctx->act;
+
+ if (key > XDP_REDIRECT)
+ key = XDP_UNKNOWN;
rec = bpf_map_lookup_elem(&exception_cnt, &key);
if (!rec)
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index 29410d551574..446668edf8d8 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -124,7 +124,8 @@ struct stats_record *alloc_stats_record(void)
rec->redir_err[0].cpu = alloc_record_per_cpu();
rec->redir_err[1].cpu = alloc_record_per_cpu();
rec->kthread.cpu = alloc_record_per_cpu();
- rec->exception.cpu = alloc_record_per_cpu();
+ for (i = 0; i < XDP_ACTION_MAX; i++)
+ rec->exception[i].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();
@@ -139,7 +140,8 @@ 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);
+ for (i = 0; i < XDP_ACTION_MAX; i++)
+ free(r->exception[i].cpu);
free(r->kthread.cpu);
free(r->redir_err[1].cpu);
free(r->redir_err[0].cpu);
@@ -388,27 +390,31 @@ static void stats_print_exception_cnt(struct stats_record *stats_rec,
struct stats_record *stats_prev,
unsigned int nr_cpus)
{
- char *fmt_err = "%-15s %-7d %'-14.0f %'-11.0f\n";
- char *fm2_err = "%-15s %-7s %'-14.0f %'-11.0f\n";
+ char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %s\n";
+ char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %s\n";
struct record *rec, *prev;
- double t, pps, drop;
- int i;
+ double t, drop;
+ int rec_i, i;
- rec = &stats_rec->exception;
- prev = &stats_prev->exception;
- t = calc_period(rec, prev);
- for (i = 0; i < nr_cpus; i++) {
- struct datarec *r = &rec->cpu[i];
- struct datarec *p = &prev->cpu[i];
+ for (rec_i = 0; rec_i < XDP_ACTION_MAX; rec_i++) {
+ rec = &stats_rec->exception[rec_i];
+ prev = &stats_prev->exception[rec_i];
+ t = calc_period(rec, prev);
- pps = calc_pps(r, p, t);
- drop = calc_drop_pps(r, p, t);
- if (pps > 0)
- printf(fmt_err, "xdp_exception", i, pps, drop);
+ for (i = 0; i < nr_cpus; i++) {
+ struct datarec *r = &rec->cpu[i];
+ struct datarec *p = &prev->cpu[i];
+
+ drop = calc_drop_pps(r, p, t);
+ if (drop > 0)
+ printf(fmt1, "xdp_exception", i,
+ 0.0, drop, action2str(rec_i));
+ }
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ if (drop > 0)
+ printf(fmt2, "xdp_exception", "total",
+ 0.0, drop, action2str(rec_i));
}
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- printf(fm2_err, "xdp_exception", "total", pps, drop);
}
void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
@@ -564,7 +570,8 @@ void sample_stats_collect(int mask, struct stats_record *rec)
map_collect_percpu(map_fds[CPUMAP_KTHREAD_CNT], 0, &rec->kthread);
if (mask & SAMPLE_EXCEPTION_CNT)
- map_collect_percpu(map_fds[EXCEPTION_CNT], 0, &rec->exception);
+ for (i = 0; i < XDP_ACTION_MAX; i++)
+ map_collect_percpu(map_fds[EXCEPTION_CNT], i, &rec->exception[i]);
if (mask & SAMPLE_DEVMAP_XMIT_CNT)
map_collect_percpu(map_fds[DEVMAP_XMIT_CNT], 0, &rec->devmap_xmit);
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index a3a3c746e73e..bc0362575d4b 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -59,12 +59,32 @@ extern int tp_cnt;
#define XDP_REDIRECT_ERR_MAX 6
-static const char *xdp_redirect_err_names[XDP_REDIRECT_ERR_MAX] = {
+__attribute__((unused)) static const char *xdp_redirect_err_names[XDP_REDIRECT_ERR_MAX] = {
/* Key=1 keeps unknown errors */
"Success", "Unknown", "EINVAL", "ENETDOWN", "EMSGSIZE",
"EOPNOTSUPP",
};
+/* enum xdp_action */
+#define XDP_UNKNOWN (XDP_REDIRECT + 1)
+#define XDP_ACTION_MAX (XDP_UNKNOWN + 1)
+
+static const char *xdp_action_names[XDP_ACTION_MAX] = {
+ [XDP_ABORTED] = "XDP_ABORTED",
+ [XDP_DROP] = "XDP_DROP",
+ [XDP_PASS] = "XDP_PASS",
+ [XDP_TX] = "XDP_TX",
+ [XDP_REDIRECT] = "XDP_REDIRECT",
+ [XDP_UNKNOWN] = "XDP_UNKNOWN",
+};
+
+__attribute__((unused)) static inline const char *action2str(int action)
+{
+ if (action < XDP_ACTION_MAX)
+ return xdp_action_names[action];
+ return NULL;
+}
+
/* Common stats data record shared with _kern.c */
struct datarec {
__u64 processed;
@@ -88,7 +108,7 @@ struct stats_record {
struct record rx_cnt;
struct record redir_err[XDP_REDIRECT_ERR_MAX];
struct record kthread;
- struct record exception;
+ struct record exception[XDP_ACTION_MAX];
struct record devmap_xmit;
struct record enq[];
};
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 09/15] samples: bpf: convert xdp_monitor to use xdp_samples
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (7 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 08/15] samples: bpf: add per exception reporting for xdp_exception Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 10/15] samples: bpf: implement terse output mode and make it default Kumar Kartikeya Dwivedi
` (5 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This reuses the samples support added so far.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/Makefile | 2 +-
samples/bpf/xdp_monitor_kern.c | 253 +------------
samples/bpf/xdp_monitor_user.c | 625 +--------------------------------
samples/bpf/xdp_sample_kern.h | 6 +-
4 files changed, 23 insertions(+), 863 deletions(-)
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index ea7100c8b760..8750233dcf07 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -102,7 +102,7 @@ xdp_redirect-objs := xdp_redirect_user.o
xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o
xdp_redirect_map-objs := xdp_redirect_map_user.o xdp_sample_user.o
xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_sample_user.o
-xdp_monitor-objs := xdp_monitor_user.o
+xdp_monitor-objs := xdp_monitor_user.o xdp_sample_user.o
xdp_rxq_info-objs := xdp_rxq_info_user.o
syscall_tp-objs := syscall_tp_user.o
cpustat-objs := cpustat_user.o
diff --git a/samples/bpf/xdp_monitor_kern.c b/samples/bpf/xdp_monitor_kern.c
index 5c955b812c47..46c4fe4d7878 100644
--- a/samples/bpf/xdp_monitor_kern.c
+++ b/samples/bpf/xdp_monitor_kern.c
@@ -3,255 +3,6 @@
*
* XDP monitor tool, based on tracepoints
*/
-#include <uapi/linux/bpf.h>
-#include <bpf/bpf_helpers.h>
+#include "xdp_sample_kern.h"
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, u64);
- __uint(max_entries, 2);
- /* TODO: have entries for all possible errno's */
-} redirect_err_cnt SEC(".maps");
-
-#define XDP_UNKNOWN XDP_REDIRECT + 1
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, u64);
- __uint(max_entries, XDP_UNKNOWN + 1);
-} exception_cnt SEC(".maps");
-
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_redirect_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12 size:4; signed:0;
- int ifindex; // offset:16 size:4; signed:1;
- int err; // offset:20 size:4; signed:1;
- int to_ifindex; // offset:24 size:4; signed:1;
- u32 map_id; // offset:28 size:4; signed:0;
- int map_index; // offset:32 size:4; signed:1;
-}; // offset:36
-
-enum {
- XDP_REDIRECT_SUCCESS = 0,
- XDP_REDIRECT_ERROR = 1
-};
-
-static __always_inline
-int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
-{
- u32 key = XDP_REDIRECT_ERROR;
- int err = ctx->err;
- u64 *cnt;
-
- if (!err)
- key = XDP_REDIRECT_SUCCESS;
-
- cnt = bpf_map_lookup_elem(&redirect_err_cnt, &key);
- if (!cnt)
- return 1;
- *cnt += 1;
-
- return 0; /* Indicate event was filtered (no further processing)*/
- /*
- * Returning 1 here would allow e.g. a perf-record tracepoint
- * to see and record these events, but it doesn't work well
- * in-practice as stopping perf-record also unload this
- * bpf_prog. Plus, there is additional overhead of doing so.
- */
-}
-
-SEC("tracepoint/xdp/xdp_redirect_err")
-int trace_xdp_redirect_err(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-
-SEC("tracepoint/xdp/xdp_redirect_map_err")
-int trace_xdp_redirect_map_err(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-/* Likely unloaded when prog starts */
-SEC("tracepoint/xdp/xdp_redirect")
-int trace_xdp_redirect(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-/* Likely unloaded when prog starts */
-SEC("tracepoint/xdp/xdp_redirect_map")
-int trace_xdp_redirect_map(struct xdp_redirect_ctx *ctx)
-{
- return xdp_redirect_collect_stat(ctx);
-}
-
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_exception_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int ifindex; // offset:16; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_exception")
-int trace_xdp_exception(struct xdp_exception_ctx *ctx)
-{
- u64 *cnt;
- u32 key;
-
- key = ctx->act;
- if (key > XDP_REDIRECT)
- key = XDP_UNKNOWN;
-
- cnt = bpf_map_lookup_elem(&exception_cnt, &key);
- if (!cnt)
- return 1;
- *cnt += 1;
-
- return 0;
-}
-
-/* Common stats data record shared with _user.c */
-struct datarec {
- u64 processed;
- u64 dropped;
- u64 info;
- u64 err;
-};
-#define MAX_CPUS 64
-
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, MAX_CPUS);
-} cpumap_enqueue_cnt SEC(".maps");
-
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 1);
-} cpumap_kthread_cnt SEC(".maps");
-
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_enqueue_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int to_cpu; // offset:28; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_enqueue")
-int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
-{
- u32 to_cpu = ctx->to_cpu;
- struct datarec *rec;
-
- if (to_cpu >= MAX_CPUS)
- return 1;
-
- rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &to_cpu);
- if (!rec)
- return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
-
- /* Record bulk events, then userspace can calc average bulk size */
- if (ctx->processed > 0)
- rec->info += 1;
-
- return 0;
-}
-
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_kthread/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_kthread_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int sched; // offset:28; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_kthread")
-int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx)
-{
- struct datarec *rec;
- u32 key = 0;
-
- rec = bpf_map_lookup_elem(&cpumap_kthread_cnt, &key);
- if (!rec)
- return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
-
- /* Count times kthread yielded CPU via schedule call */
- if (ctx->sched)
- rec->info++;
-
- return 0;
-}
-
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, u32);
- __type(value, struct datarec);
- __uint(max_entries, 1);
-} devmap_xmit_cnt SEC(".maps");
-
-/* 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->err++;
-
- /* Catch API error of drv ndo_xdp_xmit sent more than count */
- if (ctx->drops < 0)
- rec->err++;
-
- return 1;
-}
+char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index 49ebc49aefc3..babb9fcc1a17 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -30,32 +30,9 @@ static const char *__doc_err_only__=
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_util.h"
+#include "xdp_sample_user.h"
-enum map_type {
- REDIRECT_ERR_CNT,
- EXCEPTION_CNT,
- CPUMAP_ENQUEUE_CNT,
- CPUMAP_KTHREAD_CNT,
- DEVMAP_XMIT_CNT,
-};
-
-static const char *const map_type_strings[] = {
- [REDIRECT_ERR_CNT] = "redirect_err_cnt",
- [EXCEPTION_CNT] = "exception_cnt",
- [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
- [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
- [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
-};
-
-#define NUM_MAP 5
-#define NUM_TP 8
-
-static int tp_cnt;
-static int map_cnt;
-static int verbose = 1;
static bool debug = false;
-struct bpf_map *map_data[NUM_MAP] = {};
-struct bpf_link *tp_links[NUM_TP] = {};
struct bpf_object *obj;
static const struct option long_options[] = {
@@ -68,12 +45,8 @@ static const struct option long_options[] = {
static void int_exit(int sig)
{
- /* Detach tracepoints */
- while (tp_cnt)
- bpf_link__destroy(tp_links[--tp_cnt]);
-
bpf_object__close(obj);
- exit(0);
+ sample_exit(EXIT_OK);
}
/* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
@@ -100,557 +73,6 @@ static void usage(char *argv[])
printf("\n");
}
-#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
-static __u64 gettime(void)
-{
- struct timespec t;
- int res;
-
- res = clock_gettime(CLOCK_MONOTONIC, &t);
- if (res < 0) {
- fprintf(stderr, "Error with gettimeofday! (%i)\n", res);
- exit(EXIT_FAILURE);
- }
- return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
-}
-
-enum {
- REDIR_SUCCESS = 0,
- REDIR_ERROR = 1,
-};
-#define REDIR_RES_MAX 2
-static const char *redir_names[REDIR_RES_MAX] = {
- [REDIR_SUCCESS] = "Success",
- [REDIR_ERROR] = "Error",
-};
-static const char *err2str(int err)
-{
- if (err < REDIR_RES_MAX)
- return redir_names[err];
- return NULL;
-}
-/* enum xdp_action */
-#define XDP_UNKNOWN XDP_REDIRECT + 1
-#define XDP_ACTION_MAX (XDP_UNKNOWN + 1)
-static const char *xdp_action_names[XDP_ACTION_MAX] = {
- [XDP_ABORTED] = "XDP_ABORTED",
- [XDP_DROP] = "XDP_DROP",
- [XDP_PASS] = "XDP_PASS",
- [XDP_TX] = "XDP_TX",
- [XDP_REDIRECT] = "XDP_REDIRECT",
- [XDP_UNKNOWN] = "XDP_UNKNOWN",
-};
-static const char *action2str(int action)
-{
- if (action < XDP_ACTION_MAX)
- return xdp_action_names[action];
- return NULL;
-}
-
-/* Common stats data record shared with _kern.c */
-struct datarec {
- __u64 processed;
- __u64 dropped;
- __u64 info;
- __u64 err;
-};
-#define MAX_CPUS 64
-
-/* Userspace structs for collection of stats from maps */
-struct record {
- __u64 timestamp;
- struct datarec total;
- struct datarec *cpu;
-};
-struct u64rec {
- __u64 processed;
-};
-struct record_u64 {
- /* record for _kern side __u64 values */
- __u64 timestamp;
- struct u64rec total;
- struct u64rec *cpu;
-};
-
-struct stats_record {
- struct record_u64 xdp_redirect[REDIR_RES_MAX];
- struct record_u64 xdp_exception[XDP_ACTION_MAX];
- struct record xdp_cpumap_kthread;
- struct record xdp_cpumap_enqueue[MAX_CPUS];
- struct record xdp_devmap_xmit;
-};
-
-static bool map_collect_record(int fd, __u32 key, struct record *rec)
-{
- /* For percpu maps, userspace gets a value per possible CPU */
- unsigned int nr_cpus = bpf_num_possible_cpus();
- struct datarec values[nr_cpus];
- __u64 sum_processed = 0;
- __u64 sum_dropped = 0;
- __u64 sum_info = 0;
- __u64 sum_err = 0;
- int i;
-
- if ((bpf_map_lookup_elem(fd, &key, values)) != 0) {
- fprintf(stderr,
- "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
- return false;
- }
- /* Get time as close as possible to reading map contents */
- rec->timestamp = gettime();
-
- /* Record and sum values from each CPU */
- for (i = 0; i < nr_cpus; i++) {
- rec->cpu[i].processed = values[i].processed;
- sum_processed += values[i].processed;
- rec->cpu[i].dropped = values[i].dropped;
- sum_dropped += values[i].dropped;
- rec->cpu[i].info = values[i].info;
- sum_info += values[i].info;
- rec->cpu[i].err = values[i].err;
- sum_err += values[i].err;
- }
- rec->total.processed = sum_processed;
- rec->total.dropped = sum_dropped;
- rec->total.info = sum_info;
- rec->total.err = sum_err;
- return true;
-}
-
-static bool map_collect_record_u64(int fd, __u32 key, struct record_u64 *rec)
-{
- /* For percpu maps, userspace gets a value per possible CPU */
- unsigned int nr_cpus = bpf_num_possible_cpus();
- struct u64rec values[nr_cpus];
- __u64 sum_total = 0;
- int i;
-
- if ((bpf_map_lookup_elem(fd, &key, values)) != 0) {
- fprintf(stderr,
- "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
- return false;
- }
- /* Get time as close as possible to reading map contents */
- rec->timestamp = gettime();
-
- /* Record and sum values from each CPU */
- for (i = 0; i < nr_cpus; i++) {
- rec->cpu[i].processed = values[i].processed;
- sum_total += values[i].processed;
- }
- rec->total.processed = sum_total;
- return true;
-}
-
-static double calc_period(struct record *r, struct record *p)
-{
- double period_ = 0;
- __u64 period = 0;
-
- period = r->timestamp - p->timestamp;
- if (period > 0)
- period_ = ((double) period / NANOSEC_PER_SEC);
-
- return period_;
-}
-
-static double calc_period_u64(struct record_u64 *r, struct record_u64 *p)
-{
- double period_ = 0;
- __u64 period = 0;
-
- period = r->timestamp - p->timestamp;
- if (period > 0)
- period_ = ((double) period / NANOSEC_PER_SEC);
-
- return period_;
-}
-
-static double calc_pps(struct datarec *r, struct datarec *p, double period)
-{
- __u64 packets = 0;
- double pps = 0;
-
- if (period > 0) {
- packets = r->processed - p->processed;
- pps = packets / period;
- }
- return pps;
-}
-
-static double calc_pps_u64(struct u64rec *r, struct u64rec *p, double period)
-{
- __u64 packets = 0;
- double pps = 0;
-
- if (period > 0) {
- packets = r->processed - p->processed;
- pps = packets / period;
- }
- return pps;
-}
-
-static double calc_drop(struct datarec *r, struct datarec *p, double period)
-{
- __u64 packets = 0;
- double pps = 0;
-
- if (period > 0) {
- packets = r->dropped - p->dropped;
- pps = packets / period;
- }
- return pps;
-}
-
-static double calc_info(struct datarec *r, struct datarec *p, double period)
-{
- __u64 packets = 0;
- double pps = 0;
-
- if (period > 0) {
- packets = r->info - p->info;
- pps = packets / period;
- }
- return pps;
-}
-
-static double calc_err(struct datarec *r, struct datarec *p, double period)
-{
- __u64 packets = 0;
- double pps = 0;
-
- if (period > 0) {
- packets = r->err - p->err;
- pps = packets / period;
- }
- return pps;
-}
-
-static void stats_print(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- bool err_only)
-{
- unsigned int nr_cpus = bpf_num_possible_cpus();
- int rec_i = 0, i, to_cpu;
- double t = 0, pps = 0;
-
- /* Header */
- printf("%-15s %-7s %-12s %-12s %-9s\n",
- "XDP-event", "CPU:to", "pps", "drop-pps", "extra-info");
-
- /* tracepoint: xdp:xdp_redirect_* */
- if (err_only)
- rec_i = REDIR_ERROR;
-
- for (; rec_i < REDIR_RES_MAX; rec_i++) {
- struct record_u64 *rec, *prev;
- char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %s\n";
-
- rec = &stats_rec->xdp_redirect[rec_i];
- prev = &stats_prev->xdp_redirect[rec_i];
- t = calc_period_u64(rec, prev);
-
- for (i = 0; i < nr_cpus; i++) {
- struct u64rec *r = &rec->cpu[i];
- struct u64rec *p = &prev->cpu[i];
-
- pps = calc_pps_u64(r, p, t);
- if (pps > 0)
- printf(fmt1, "XDP_REDIRECT", i,
- rec_i ? 0.0: pps, rec_i ? pps : 0.0,
- err2str(rec_i));
- }
- pps = calc_pps_u64(&rec->total, &prev->total, t);
- printf(fmt2, "XDP_REDIRECT", "total",
- rec_i ? 0.0: pps, rec_i ? pps : 0.0, err2str(rec_i));
- }
-
- /* tracepoint: xdp:xdp_exception */
- for (rec_i = 0; rec_i < XDP_ACTION_MAX; rec_i++) {
- struct record_u64 *rec, *prev;
- char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %s\n";
-
- rec = &stats_rec->xdp_exception[rec_i];
- prev = &stats_prev->xdp_exception[rec_i];
- t = calc_period_u64(rec, prev);
-
- for (i = 0; i < nr_cpus; i++) {
- struct u64rec *r = &rec->cpu[i];
- struct u64rec *p = &prev->cpu[i];
-
- pps = calc_pps_u64(r, p, t);
- if (pps > 0)
- printf(fmt1, "Exception", i,
- 0.0, pps, action2str(rec_i));
- }
- pps = calc_pps_u64(&rec->total, &prev->total, t);
- if (pps > 0)
- printf(fmt2, "Exception", "total",
- 0.0, pps, action2str(rec_i));
- }
-
- /* cpumap enqueue stats */
- for (to_cpu = 0; to_cpu < MAX_CPUS; to_cpu++) {
- char *fmt1 = "%-15s %3d:%-3d %'-12.0f %'-12.0f %'-10.2f %s\n";
- char *fmt2 = "%-15s %3s:%-3d %'-12.0f %'-12.0f %'-10.2f %s\n";
- struct record *rec, *prev;
- char *info_str = "";
- double drop, info;
-
- rec = &stats_rec->xdp_cpumap_enqueue[to_cpu];
- prev = &stats_prev->xdp_cpumap_enqueue[to_cpu];
- 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(r, p, t);
- info = calc_info(r, p, t);
- if (info > 0) {
- info_str = "bulk-average";
- info = pps / info; /* calc average bulk size */
- }
- if (pps > 0)
- printf(fmt1, "cpumap-enqueue",
- i, to_cpu, pps, drop, info, info_str);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- if (pps > 0) {
- drop = calc_drop(&rec->total, &prev->total, t);
- info = calc_info(&rec->total, &prev->total, t);
- if (info > 0) {
- info_str = "bulk-average";
- info = pps / info; /* calc average bulk size */
- }
- printf(fmt2, "cpumap-enqueue",
- "sum", to_cpu, pps, drop, info, info_str);
- }
- }
-
- /* cpumap kthread stats */
- {
- char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %'-10.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %'-10.0f %s\n";
- struct record *rec, *prev;
- double drop, info;
- char *i_str = "";
-
- rec = &stats_rec->xdp_cpumap_kthread;
- prev = &stats_prev->xdp_cpumap_kthread;
- 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(r, p, t);
- info = calc_info(r, p, t);
- if (info > 0)
- i_str = "sched";
- if (pps > 0 || drop > 0)
- printf(fmt1, "cpumap-kthread",
- i, pps, drop, info, i_str);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop(&rec->total, &prev->total, t);
- info = calc_info(&rec->total, &prev->total, t);
- if (info > 0)
- i_str = "sched-sum";
- printf(fmt2, "cpumap-kthread", "total", pps, drop, info, i_str);
- }
-
- /* devmap ndo_xdp_xmit stats */
- {
- char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %'-10.2f %s %s\n";
- char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %'-10.2f %s %s\n";
- struct record *rec, *prev;
- double drop, info, err;
- char *i_str = "";
- char *err_str = "";
-
- rec = &stats_rec->xdp_devmap_xmit;
- prev = &stats_prev->xdp_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(r, p, t);
- info = calc_info(r, p, t);
- err = calc_err(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(&rec->total, &prev->total, t);
- info = calc_info(&rec->total, &prev->total, t);
- err = calc_err(&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);
- }
-
- printf("\n");
-}
-
-static bool stats_collect(struct stats_record *rec)
-{
- int fd;
- int i;
-
- /* TODO: Detect if someone unloaded the perf event_fd's, as
- * this can happen by someone running perf-record -e
- */
-
- fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
- for (i = 0; i < REDIR_RES_MAX; i++)
- map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
-
- fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
- for (i = 0; i < XDP_ACTION_MAX; i++) {
- map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
- }
-
- fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
- for (i = 0; i < MAX_CPUS; i++)
- map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
-
- fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
- map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
-
- fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
- map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
-
- return true;
-}
-
-static void *alloc_rec_per_cpu(int record_size)
-{
- unsigned int nr_cpus = bpf_num_possible_cpus();
- void *array;
-
- array = calloc(nr_cpus, record_size);
- if (!array) {
- fprintf(stderr, "Mem alloc error (nr_cpus:%u)\n", nr_cpus);
- exit(EXIT_FAIL_MEM);
- }
- return array;
-}
-
-static struct stats_record *alloc_stats_record(void)
-{
- struct stats_record *rec;
- int rec_sz;
- int i;
-
- /* Alloc main stats_record structure */
- rec = calloc(1, sizeof(*rec));
- if (!rec) {
- fprintf(stderr, "Mem alloc error\n");
- exit(EXIT_FAIL_MEM);
- }
-
- /* Alloc stats stored per CPU for each record */
- rec_sz = sizeof(struct u64rec);
- for (i = 0; i < REDIR_RES_MAX; i++)
- rec->xdp_redirect[i].cpu = alloc_rec_per_cpu(rec_sz);
-
- for (i = 0; i < XDP_ACTION_MAX; i++)
- rec->xdp_exception[i].cpu = alloc_rec_per_cpu(rec_sz);
-
- rec_sz = sizeof(struct datarec);
- rec->xdp_cpumap_kthread.cpu = alloc_rec_per_cpu(rec_sz);
- rec->xdp_devmap_xmit.cpu = alloc_rec_per_cpu(rec_sz);
-
- for (i = 0; i < MAX_CPUS; i++)
- rec->xdp_cpumap_enqueue[i].cpu = alloc_rec_per_cpu(rec_sz);
-
- return rec;
-}
-
-static void free_stats_record(struct stats_record *r)
-{
- int i;
-
- for (i = 0; i < REDIR_RES_MAX; i++)
- free(r->xdp_redirect[i].cpu);
-
- for (i = 0; i < XDP_ACTION_MAX; i++)
- free(r->xdp_exception[i].cpu);
-
- free(r->xdp_cpumap_kthread.cpu);
- free(r->xdp_devmap_xmit.cpu);
-
- for (i = 0; i < MAX_CPUS; i++)
- free(r->xdp_cpumap_enqueue[i].cpu);
-
- free(r);
-}
-
-/* Pointer swap trick */
-static inline void swap(struct stats_record **a, struct stats_record **b)
-{
- struct stats_record *tmp;
-
- tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
-static void stats_poll(int interval, bool err_only)
-{
- struct stats_record *rec, *prev;
-
- rec = alloc_stats_record();
- prev = alloc_stats_record();
- stats_collect(rec);
-
- if (err_only)
- printf("\n%s\n", __doc_err_only__);
-
- /* Trick to pretty printf with thousands separators use %' */
- setlocale(LC_NUMERIC, "en_US");
-
- /* Header */
- if (verbose)
- printf("\n%s", __doc__);
-
- /* TODO Need more advanced stats on error types */
- if (verbose) {
- printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
- printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
- printf("\n");
- }
- fflush(stdout);
-
- while (1) {
- swap(&prev, &rec);
- stats_collect(rec);
- stats_print(rec, prev, err_only);
- fflush(stdout);
- sleep(interval);
- }
-
- free_stats_record(rec);
- free_stats_record(prev);
-}
-
static void print_bpf_prog_info(void)
{
struct bpf_program *prog;
@@ -666,7 +88,7 @@ static void print_bpf_prog_info(void)
i = 0;
/* Maps info */
- printf("Loaded BPF prog have %d map(s)\n", map_cnt);
+ printf("Loaded BPF prog have %d map(s)\n", NUM_MAP);
bpf_object__for_each_map(map, obj) {
const char *name = bpf_map__name(map);
int fd = bpf_map__fd(map);
@@ -687,10 +109,11 @@ static void print_bpf_prog_info(void)
int main(int argc, char **argv)
{
- struct bpf_program *prog;
+ int mask = SAMPLE_REDIRECT_ERR_CNT | SAMPLE_CPUMAP_ENQUEUE_CNT |
+ SAMPLE_CPUMAP_KTHREAD_CNT | SAMPLE_EXCEPTION_CNT |
+ SAMPLE_DEVMAP_XMIT_CNT;
int longindex = 0, opt;
int ret = EXIT_FAILURE;
- enum map_type type;
char filename[256];
/* Default settings: */
@@ -736,25 +159,9 @@ int main(int argc, char **argv)
goto cleanup;
}
- for (type = 0; type < NUM_MAP; type++) {
- map_data[type] =
- bpf_object__find_map_by_name(obj, map_type_strings[type]);
-
- if (libbpf_get_error(map_data[type])) {
- printf("ERROR: finding a map in obj file failed\n");
- goto cleanup;
- }
- map_cnt++;
- }
-
- bpf_object__for_each_program(prog, obj) {
- tp_links[tp_cnt] = bpf_program__attach(prog);
- if (libbpf_get_error(tp_links[tp_cnt])) {
- printf("ERROR: bpf_program__attach failed\n");
- tp_links[tp_cnt] = NULL;
- goto cleanup;
- }
- tp_cnt++;
+ if (sample_init(obj) < 0) {
+ fprintf(stderr, "Failed to initialize sample\n");
+ goto cleanup;
}
if (debug) {
@@ -763,6 +170,8 @@ int main(int argc, char **argv)
/* Unload/stop tracepoint event by closing bpf_link's */
if (errors_only) {
+ printf("%s", __doc_err_only__);
+
/* The bpf_link[i] depend on the order of
* the functions was defined in _kern.c
*/
@@ -771,17 +180,13 @@ int main(int argc, char **argv)
bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
tp_links[3] = NULL;
+ } else {
+ mask |= SAMPLE_REDIRECT_CNT;
}
- stats_poll(interval, errors_only);
-
- ret = EXIT_SUCCESS;
+ sample_stats_poll(interval, mask, "xdp_monitor", true);
cleanup:
- /* Detach tracepoints */
- while (tp_cnt)
- bpf_link__destroy(tp_links[--tp_cnt]);
-
bpf_object__close(obj);
- return ret;
+ sample_exit(EXIT_OK);
}
diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
index ec36e7b4a3ba..dd7f7ea63166 100644
--- a/samples/bpf/xdp_sample_kern.h
+++ b/samples/bpf/xdp_sample_kern.h
@@ -5,7 +5,11 @@
#include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h>
-#define MAX_CPUS 64
+#ifndef NR_CPUS
+#define NR_CPUS 64
+#endif
+
+#define MAX_CPUS NR_CPUS
#define EINVAL 22
#define ENETDOWN 100
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 10/15] samples: bpf: implement terse output mode and make it default
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (8 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 09/15] samples: bpf: convert xdp_monitor to use xdp_samples Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 11/15] samples: bpf: print summary of session on exit Kumar Kartikeya Dwivedi
` (4 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
Also allow an easy way to go back to the verbose output using Ctrl+\
(SIGQUIT).
One change we make to exception printing is that we skip the per CPU per
action exception count printing (not collection), as it isn't too useful
in general.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/Makefile | 2 +-
samples/bpf/xdp_monitor_user.c | 2 +-
samples/bpf/xdp_redirect_cpu_user.c | 6 +-
samples/bpf/xdp_sample_user.c | 522 +++++++++++++++++++---------
samples/bpf/xdp_sample_user.h | 36 ++
5 files changed, 402 insertions(+), 166 deletions(-)
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 8750233dcf07..d1977fe56dce 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -194,7 +194,7 @@ BPF_EXTRA_CFLAGS += -I$(srctree)/arch/mips/include/asm/mach-generic
endif
endif
-TPROGS_CFLAGS += -Wall -O2
+TPROGS_CFLAGS += -Wall -O2 -lm
TPROGS_CFLAGS += -Wmissing-prototypes
TPROGS_CFLAGS += -Wstrict-prototypes
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index babb9fcc1a17..73d6d35f0c65 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -184,7 +184,7 @@ int main(int argc, char **argv)
mask |= SAMPLE_REDIRECT_CNT;
}
- sample_stats_poll(interval, mask, "xdp_monitor", true);
+ sample_stats_poll(interval, mask, NULL, true);
cleanup:
bpf_object__close(obj);
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 6dbed962a2e2..3983ed71d879 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -216,16 +216,18 @@ static void __stats_poll(int interval, bool use_separators, char *prog_name,
for (;;) {
swap(&prev, &record);
sample_stats_collect(mask, record);
- sample_stats_print(mask, record, prev, prog_name);
+ sample_stats_print(mask, record, prev, NULL);
/* Depends on SAMPLE_CPUMAP_KTHREAD_CNT */
sample_stats_print_cpumap_remote(record, prev,
bpf_num_possible_cpus(),
mprog_name);
- printf("\n");
+ if (sample_log_level & LL_DEFAULT)
+ printf("\n");
fflush(stdout);
sleep(interval);
if (stress_mode)
stress_cpumap(value);
+ sample_reset_mode();
}
free_stats_record(record);
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index 446668edf8d8..d0b26023f1db 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -9,7 +9,9 @@
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
+#include <math.h>
#include <locale.h>
+#include <sys/signalfd.h>
#include <sys/resource.h>
#include <sys/sysinfo.h>
#include <getopt.h>
@@ -35,6 +37,39 @@
struct bpf_link *tp_links[NUM_TP] = {};
int map_fds[NUM_MAP], tp_cnt, n_cpus;
+static int sample_sig_fd;
+enum log_level sample_log_level = LL_SIMPLE;
+static bool err_exp;
+
+#define __sample_print(fmt, cond, printer, ...) \
+ ({ \
+ if (cond) \
+ printer(fmt, ##__VA_ARGS__); \
+ })
+
+#define print_always(fmt, ...) __sample_print(fmt, 1, printf, ##__VA_ARGS__)
+#define print_default(fmt, ...) \
+ __sample_print(fmt, sample_log_level & LL_DEFAULT, printf, ##__VA_ARGS__)
+#define __print_err(err, fmt, printer, ...) \
+ ({ \
+ __sample_print(fmt, err > 0 || sample_log_level & LL_DEFAULT, \
+ printer, ##__VA_ARGS__); \
+ err_exp = err_exp ? true : err > 0; \
+ })
+#define print_err(err, fmt, ...) __print_err(err, fmt, printf, ##__VA_ARGS__)
+
+#define __COLUMN(x) "%'10" x " %-13s"
+#define FMT_COLUMNf __COLUMN(".0f")
+#define FMT_COLUMNd __COLUMN("d")
+#define FMT_COLUMNl __COLUMN("llu")
+#define RX(rx) rx, "rx/s"
+#define PPS(pps) pps, "pkt/s"
+#define DROP(drop) drop, "drop/s"
+#define ERR(err) err, "error/s"
+#define HITS(hits) hits, "hit/s"
+#define XMIT(xmit) xmit, "xmit/s"
+#define PASS(pass) pass, "pass/s"
+#define REDIR(redir) redir, "redir/s"
#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
static __u64 gettime(void)
@@ -121,8 +156,8 @@ struct stats_record *alloc_stats_record(void)
}
memset(rec, 0, size);
rec->rx_cnt.cpu = alloc_record_per_cpu();
- rec->redir_err[0].cpu = alloc_record_per_cpu();
- rec->redir_err[1].cpu = alloc_record_per_cpu();
+ for (i = 0; i < XDP_REDIRECT_ERR_MAX; i++)
+ rec->redir_err[i].cpu = alloc_record_per_cpu();
rec->kthread.cpu = alloc_record_per_cpu();
for (i = 0; i < XDP_ACTION_MAX; i++)
rec->exception[i].cpu = alloc_record_per_cpu();
@@ -143,8 +178,8 @@ void free_stats_record(struct stats_record *r)
for (i = 0; i < XDP_ACTION_MAX; i++)
free(r->exception[i].cpu);
free(r->kthread.cpu);
- free(r->redir_err[1].cpu);
- free(r->redir_err[0].cpu);
+ for (i = 0; i < XDP_REDIRECT_ERR_MAX; i++)
+ free(r->redir_err[i].cpu);
free(r->rx_cnt.cpu);
free(r);
}
@@ -161,6 +196,13 @@ static double calc_period(struct record *r, struct record *p)
return period_;
}
+static double sample_round(double val)
+{
+ if (val - floor(val) < 0.5)
+ return floor(val);
+ return ceil(val);
+}
+
static __u64 calc_pps(struct datarec *r, struct datarec *p, double period_)
{
__u64 packets = 0;
@@ -168,7 +210,7 @@ static __u64 calc_pps(struct datarec *r, struct datarec *p, double period_)
if (period_ > 0) {
packets = r->processed - p->processed;
- pps = packets / period_;
+ pps = sample_round(packets / period_);
}
return pps;
}
@@ -180,7 +222,7 @@ static __u64 calc_drop_pps(struct datarec *r, struct datarec *p, double period_)
if (period_ > 0) {
packets = r->dropped - p->dropped;
- pps = packets / period_;
+ pps = sample_round(packets / period_);
}
return pps;
}
@@ -193,7 +235,7 @@ static __u64 calc_errs_pps(struct datarec *r,
if (period_ > 0) {
packets = r->issue - p->issue;
- pps = packets / period_;
+ pps = sample_round(packets / period_);
}
return pps;
}
@@ -206,7 +248,7 @@ static __u64 calc_info_pps(struct datarec *r,
if (period_ > 0) {
packets = r->info - p->info;
- pps = packets / period_;
+ pps = sample_round(packets / period_);
}
return pps;
}
@@ -223,41 +265,52 @@ static void calc_xdp_pps(struct datarec *r, struct datarec *p,
}
}
-static void stats_print_rx_cnt(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_rx_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, struct sample_output *out)
{
- char *fmt_rx = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
- char *fm2_rx = "%-15s %-7s %'-14.0f %'-11.0f\n";
struct record *rec, *prev;
double t, pps, drop, err;
- char *errstr = "";
int i;
rec = &stats_rec->rx_cnt;
prev = &stats_prev->rx_cnt;
t = calc_period(rec, prev);
+
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
pps = calc_pps(r, p, t);
+ if (!pps)
+ continue;
+
+ snprintf(str, sizeof(str), "cpu:%d", i);
+
drop = calc_drop_pps(r, p, t);
err = calc_errs_pps(r, p, t);
- if (err > 0)
- errstr = "cpu-dest/err";
- if (pps > 0)
- printf(fmt_rx, "XDP-RX", i, pps, drop, err, errstr);
+ print_default(" %-12s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n",
+ str, PPS(pps), DROP(drop), ERR(err));
+ }
+
+ if (out) {
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+
+ out->rx_cnt.pps = pps;
+ out->rx_cnt.drop = drop;
+ out->rx_cnt.err = err;
+ out->totals.rx += pps;
+ out->totals.drop += drop;
+ out->totals.err += err;
}
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- printf(fm2_rx, "XDP-RX", "total", pps, drop);
}
-static void stats_print_cpumap_enqueue(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_cpumap_enqueue(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
{
struct record *rec, *prev;
double t, pps, drop, err;
@@ -265,83 +318,88 @@ static void stats_print_cpumap_enqueue(struct stats_record *stats_rec,
/* cpumap enqueue stats */
for (to_cpu = 0; to_cpu < n_cpus; to_cpu++) {
- char *fmt = "%-15s %3d:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
- char *fm2 = "%-15s %3s:%-3d %'-14.0f %'-11.0f %'-10.2f %s\n";
- char *errstr = "";
-
rec = &stats_rec->enq[to_cpu];
prev = &stats_prev->enq[to_cpu];
t = calc_period(rec, prev);
+
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+
+ if (pps > 0) {
+ char str[256];
+
+ snprintf(str, sizeof(str), "enqueue to cpu %d", to_cpu);
+
+ if (err > 0)
+ err = pps / err; /* calc average bulk size */
+ print_default(" %-20s " FMT_COLUMNf FMT_COLUMNf __COLUMN(".2f") "\n",
+ str, PPS(pps), DROP(drop), err, "bulk_avg");
+ }
+
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
pps = calc_pps(r, p, t);
+ if (!pps)
+ continue;
+
+ snprintf(str, sizeof(str), "cpu:%d->%d", i, to_cpu);
+
drop = calc_drop_pps(r, p, t);
err = calc_errs_pps(r, p, t);
- if (err > 0) {
- errstr = "bulk-average";
- err = pps / err; /* calc average bulk size */
- }
- if (pps > 0)
- printf(fmt, "cpumap-enqueue",
- i, to_cpu, pps, drop, err, errstr);
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- if (pps > 0) {
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- if (err > 0) {
- errstr = "bulk-average";
+ if (err > 0)
err = pps / err; /* calc average bulk size */
- }
- printf(fm2, "cpumap-enqueue",
- "sum", to_cpu, pps, drop, err, errstr);
+ print_default(" %-12s " FMT_COLUMNf FMT_COLUMNf
+ __COLUMN(".2f") "\n", str, PPS(pps), DROP(drop),
+ err, "bulk_avg");
}
}
}
-static void stats_print_cpumap_kthread(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_cpumap_kthread(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus)
{
- char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f %s\n";
- char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f %s\n";
struct record *rec, *prev;
double t, pps, drop, err;
- char *e_str = "";
int i;
rec = &stats_rec->kthread;
prev = &stats_prev->kthread;
t = calc_period(rec, prev);
+
+ pps = calc_pps(&rec->total, &prev->total, t);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+
+ print_default(" %-20s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n", "kthread total",
+ PPS(pps), DROP(drop), err, "sched");
+
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
pps = calc_pps(r, p, t);
+ if (!pps)
+ continue;
+
+ snprintf(str, sizeof(str), "cpu:%d", i);
+
drop = calc_drop_pps(r, p, t);
err = calc_errs_pps(r, p, t);
- if (err > 0)
- e_str = "sched";
- if (pps > 0)
- printf(fmt_k, "cpumap_kthread", i, pps, drop, err,
- e_str);
+ print_default(" %-12s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n",
+ str, PPS(pps), DROP(drop), err, "sched");
}
- pps = calc_pps(&rec->total, &prev->total, t);
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- err = calc_errs_pps(&rec->total, &prev->total, t);
- if (err > 0)
- e_str = "sched-sum";
- printf(fm2_k, "cpumap_kthread", "total", pps, drop, err, e_str);
}
-static void stats_print_redirect_cnt(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_redirect_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, struct sample_output *out)
{
- char *fmt1 = "%-15s %-7d %'-14.0f %'-11.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-14.0f %'-11.0f %s\n";
struct record *rec, *prev;
double t, pps;
int i;
@@ -352,68 +410,106 @@ static void stats_print_redirect_cnt(struct stats_record *stats_rec,
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
pps = calc_pps(r, p, t);
- if (pps > 0)
- printf(fmt1, "redirect", i, pps, 0.0, "Success");
- }
- pps = calc_pps(&rec->total, &prev->total, t);
- printf(fmt2, "redirect", "total", pps, 0.0, "Success");
-}
+ if (!pps)
+ continue;
-static void stats_print_redirect_err_cnt(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
-{
- char *fmt1 = "%-15s %-7d %'-14.0f %'-11.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-14.0f %'-11.0f %s\n";
- struct record *rec, *prev;
- double t, drop;
- int i;
+ snprintf(str, sizeof(str), "cpu:%d", i);
- rec = &stats_rec->redir_err[1];
- prev = &stats_prev->redir_err[1];
- t = calc_period(rec, prev);
- for (i = 0; i < nr_cpus; i++) {
- struct datarec *r = &rec->cpu[i];
- struct datarec *p = &prev->cpu[i];
+ print_default(" %-11s " FMT_COLUMNf "\n", str, REDIR(pps));
+ }
- drop = calc_drop_pps(r, p, t);
- if (drop > 0)
- printf(fmt1, "redirect", i, 0.0, drop, "Error");
+ if (out) {
+ pps = calc_pps(&rec->total, &prev->total, t);
+ out->redir_cnt.suc = pps;
+ out->totals.redir += pps;
}
- drop = calc_drop_pps(&rec->total, &prev->total, t);
- printf(fmt2, "redirect", "total", 0.0, drop, "Error");
+
}
-static void stats_print_exception_cnt(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_redirect_err_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, struct sample_output *out)
{
- char *fmt1 = "%-15s %-7d %'-12.0f %'-12.0f %s\n";
- char *fmt2 = "%-15s %-7s %'-12.0f %'-12.0f %s\n";
struct record *rec, *prev;
- double t, drop;
+ double t, drop, sum = 0;
int rec_i, i;
- for (rec_i = 0; rec_i < XDP_ACTION_MAX; rec_i++) {
- rec = &stats_rec->exception[rec_i];
- prev = &stats_prev->exception[rec_i];
+ for (rec_i = 1; rec_i < XDP_REDIRECT_ERR_MAX; rec_i++) {
+ char str[256];
+ int l = 0;
+
+ rec = &stats_rec->redir_err[rec_i];
+ prev = &stats_prev->redir_err[rec_i];
t = calc_period(rec, prev);
+ drop = calc_drop_pps(&rec->total, &prev->total, t);
+ if (drop > 0 && !out) {
+ l = snprintf(str, sizeof(str),
+ sample_log_level & LL_DEFAULT ?
+ "%s total" :
+ "%s",
+ xdp_redirect_err_names[rec_i]);
+ l = l >= sizeof(str) ? sizeof(str) - 1 : l;
+ print_err(drop, " %-18s " FMT_COLUMNf "\n", str,
+ ERR(drop));
+ }
+
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ double drop;
+ int sp, ll;
drop = calc_drop_pps(r, p, t);
- if (drop > 0)
- printf(fmt1, "xdp_exception", i,
- 0.0, drop, action2str(rec_i));
+ if (!drop)
+ continue;
+
+ ll = snprintf(str, sizeof(str), "cpu:%d", i);
+ ll = ll >= sizeof(str) ? sizeof(str) - 1 : ll;
+
+ sp = l - ll > 0 ? l - ll : 0;
+ ll = 19 - sp > 0 ? 19 - sp : 0;
+
+ /* Align dynamically under error string */
+ print_default(" %*c%-*s" FMT_COLUMNf "\n", sp, ' ', ll, str, ERR(drop));
}
+
+ sum += drop;
+ }
+
+ if (out) {
+ out->redir_cnt.err = sum;
+ out->totals.err += sum;
+ }
+}
+
+static void stats_get_exception_cnt(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, struct sample_output *out)
+{
+ double t, drop, sum = 0;
+ struct record *rec, *prev;
+ int rec_i;
+
+
+ for (rec_i = 0; rec_i < XDP_ACTION_MAX; rec_i++) {
+ rec = &stats_rec->exception[rec_i];
+ prev = &stats_prev->exception[rec_i];
+ t = calc_period(rec, prev);
+
drop = calc_drop_pps(&rec->total, &prev->total, t);
- if (drop > 0)
- printf(fmt2, "xdp_exception", "total",
- 0.0, drop, action2str(rec_i));
+ /* Fold out errors after heading */
+ if (drop > 0 && !out)
+ print_always(" %-18s " FMT_COLUMNf "\n", action2str(rec_i), ERR(drop));
+ sum += drop;
+ }
+
+ if (out) {
+ out->except_cnt.hits = sum;
+ out->totals.err += sum;
}
}
@@ -421,16 +517,12 @@ void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
struct stats_record *stats_prev,
unsigned int nr_cpus, char *mprog_name)
{
- char *fmt_k = "%-15s %-7d %'-14.0f %'-11.0f %'-10.0f\n";
- char *fm2_k = "%-15s %-7s %'-14.0f %'-11.0f %'-10.0f\n";
double xdp_pass, xdp_drop, xdp_redirect;
struct record *rec, *prev;
double t;
int i;
- printf("\n2nd remote XDP/eBPF prog_name: %s\n", mprog_name ?: "(none)");
- printf("%-15s %-7s %-14s %-11s %-9s\n", "XDP-cpumap", "CPU:to",
- "xdp-pass", "xdp-drop", "xdp-redir");
+ print_default("\n2nd remote XDP/eBPF prog_name: %s\n", mprog_name ?: "(none)");
rec = &stats_rec->kthread;
prev = &stats_prev->kthread;
@@ -438,28 +530,28 @@ void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
calc_xdp_pps(r, p, &xdp_pass, &xdp_drop, &xdp_redirect, t);
- if (xdp_pass > 0 || xdp_drop > 0 || xdp_redirect > 0)
- printf(fmt_k, "xdp-in-kthread", i, xdp_pass, xdp_drop,
- xdp_redirect);
+ if (!xdp_pass || !xdp_drop || !xdp_redirect)
+ continue;
+
+ snprintf(str, sizeof(str), "cpu:%d", i);
+ print_default(" %-5s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n",
+ str, PASS(xdp_pass), DROP(xdp_drop), REDIR(xdp_redirect));
}
calc_xdp_pps(&rec->total, &prev->total, &xdp_pass, &xdp_drop,
&xdp_redirect, t);
- printf(fm2_k, "xdp-in-kthread", "total", xdp_pass, xdp_drop,
- xdp_redirect);
+ print_default(" %-20s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n",
+ "xdp_in_kthread total", PASS(xdp_pass), DROP(xdp_drop), REDIR(xdp_redirect));
}
-static void stats_print_devmap_xmit(struct stats_record *stats_rec,
- struct stats_record *stats_prev,
- unsigned int nr_cpus)
+static void stats_get_devmap_xmit(struct stats_record *stats_rec,
+ struct stats_record *stats_prev,
+ unsigned int nr_cpus, struct sample_output *out)
{
- 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;
@@ -469,32 +561,114 @@ static void stats_print_devmap_xmit(struct stats_record *stats_rec,
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
struct datarec *p = &prev->cpu[i];
+ char str[256];
pps = calc_pps(r, p, t);
drop = calc_drop_pps(r, p, t);
+
+ if (!pps)
+ continue;
+
+ snprintf(str, sizeof(str), "cpu:%d", i);
+
info = calc_info_pps(r, p, t);
err = calc_errs_pps(r, p, t);
- if (info > 0) {
- i_str = "bulk-average";
+ if (info > 0)
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);
+ print_default(" %-9s" FMT_COLUMNf FMT_COLUMNf
+ FMT_COLUMNf __COLUMN(".2f") "\n",
+ str, XMIT(pps), DROP(drop), err, "drv_err/s",
+ info, "bulk_avg");
}
- 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 (out) {
+ 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);
+ if (info > 0)
+ info = (pps + drop) / info; /* calc avg bulk */
+ err = calc_errs_pps(&rec->total, &prev->total, t);
+
+ out->xmit_cnt.pps = pps;
+ out->xmit_cnt.drop = drop;
+ out->xmit_cnt.bavg = info;
+ out->xmit_cnt.err = err;
+ out->totals.xmit += pps;
+ out->totals.err += err;
+ }
+}
+
+static void stats_print(const char *prefix, int mask, struct stats_record *r,
+ struct stats_record *p, struct sample_output *out)
+{
+ int nr_cpus = bpf_num_possible_cpus();
+ const char *str;
+
+ print_always("%-23s", prefix ?: "Summary");
+ if (mask & SAMPLE_RX_CNT)
+ print_always(FMT_COLUMNl, RX(out->totals.rx));
+ if (mask & SAMPLE_REDIRECT_CNT)
+ print_always(FMT_COLUMNl, REDIR(out->totals.redir));
+ printf(FMT_COLUMNl, ERR(out->totals.err + out->totals.drop));
+ if (mask & SAMPLE_DEVMAP_XMIT_CNT)
+ printf(FMT_COLUMNl, XMIT(out->totals.xmit));
+ printf("\n");
+
+ if (mask & SAMPLE_RX_CNT) {
+ str = (sample_log_level & LL_DEFAULT) && out->rx_cnt.pps ?
+ "receive total" : "receive";
+ print_err(
+ (out->rx_cnt.err || out->rx_cnt.drop),
+ " %-20s " FMT_COLUMNl FMT_COLUMNl FMT_COLUMNl "\n",
+ str, PPS(out->rx_cnt.pps), DROP(out->rx_cnt.drop),
+ ERR(out->rx_cnt.err));
+
+ stats_get_rx_cnt(r, p, nr_cpus, NULL);
+ }
+
+ if (mask & SAMPLE_CPUMAP_ENQUEUE_CNT)
+ stats_get_cpumap_enqueue(r, p, nr_cpus);
+ if (mask & SAMPLE_CPUMAP_KTHREAD_CNT)
+ stats_get_cpumap_kthread(r, p, nr_cpus);
+
+ if (mask & SAMPLE_REDIRECT_CNT) {
+ str = out->redir_cnt.suc ? "redirect total" : "redirect";
+ print_default(" %-20s " FMT_COLUMNl "\n", str, REDIR(out->redir_cnt.suc));
+
+ stats_get_redirect_cnt(r, p, nr_cpus, NULL);
+ }
+
+ if (mask & SAMPLE_REDIRECT_ERR_CNT) {
+ str = (sample_log_level & LL_DEFAULT) && out->redir_cnt.err ?
+ "redirect_err total" : "redirect_err";
+ print_err(out->redir_cnt.err, " %-20s " FMT_COLUMNl "\n", str,
+ ERR(out->redir_cnt.err));
+
+ stats_get_redirect_err_cnt(r, p, nr_cpus, NULL);
+ }
+
+ if (mask & SAMPLE_EXCEPTION_CNT) {
+ str = out->except_cnt.hits ? "xdp_exception total" : "xdp_exception";
+ print_err(out->except_cnt.hits, " %-20s " FMT_COLUMNl "\n",
+ str, HITS(out->except_cnt.hits));
+
+ stats_get_exception_cnt(r, p, nr_cpus, NULL);
+ }
+
+ if (mask & SAMPLE_DEVMAP_XMIT_CNT) {
+ str = (sample_log_level & LL_DEFAULT) && out->xmit_cnt.pps ?
+ "devmap_xmit total" : "devmap_xmit";
+ print_err(out->xmit_cnt.err,
+ " %-20s " FMT_COLUMNl FMT_COLUMNl FMT_COLUMNl __COLUMN(".2f") "\n",
+ str, XMIT(out->xmit_cnt.pps), DROP(out->xmit_cnt.drop),
+ out->xmit_cnt.err, "drv_err/s", out->xmit_cnt.bavg, "bulk_avg");
+
+ stats_get_devmap_xmit(r, p, nr_cpus, NULL);
+ }
+
+ if (sample_log_level & LL_DEFAULT || ((sample_log_level & LL_SIMPLE) && err_exp)) {
+ err_exp = false;
+ printf("\n");
}
- 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)
@@ -534,15 +708,47 @@ static int init_map_fds(struct bpf_object *obj)
int sample_init(struct bpf_object *obj)
{
+ sigset_t st;
+
n_cpus = get_nprocs_conf();
+
+ sigemptyset(&st);
+ sigaddset(&st, SIGQUIT);
+
+ if (sigprocmask(SIG_BLOCK, &st, NULL) < 0)
+ return -errno;
+
+ sample_sig_fd = signalfd(-1, &st, SFD_CLOEXEC|SFD_NONBLOCK);
+ if (sample_sig_fd < 0)
+ return -errno;
+
return init_tracepoints(obj) ? : init_map_fds(obj);
}
+void sample_reset_mode(void)
+{
+ struct signalfd_siginfo si;
+ int r;
+
+ r = read(sample_sig_fd, &si, sizeof(si));
+ if (r < 0) {
+ if (errno == EAGAIN)
+ return;
+ return;
+ }
+
+ if (si.ssi_signo == SIGQUIT) {
+ sample_log_level ^= LL_DEBUG - 1;
+ printf("\n");
+ }
+}
+
void sample_exit(int status)
{
while (tp_cnt)
bpf_link__destroy(tp_links[--tp_cnt]);
+ close(sample_sig_fd);
exit(status);
}
@@ -580,32 +786,24 @@ void sample_stats_collect(int mask, struct stats_record *rec)
void sample_stats_print(int mask, struct stats_record *cur,
struct stats_record *prev, char *prog_name)
{
- int nr_cpus = bpf_num_possible_cpus();
-
- printf("Running XDP/eBPF prog_name:%s\n", prog_name ?: "(none)");
- printf("%-15s %-7s %-14s %-11s %-9s\n",
- "XDP-event", "CPU:to", "pps", "drop-pps", "extra-info");
+ struct sample_output out = {};
if (mask & SAMPLE_RX_CNT)
- stats_print_rx_cnt(cur, prev, nr_cpus);
+ stats_get_rx_cnt(cur, prev, 0, &out);
if (mask & SAMPLE_REDIRECT_CNT)
- stats_print_redirect_cnt(cur, prev, nr_cpus);
+ stats_get_redirect_cnt(cur, prev, 0, &out);
if (mask & SAMPLE_REDIRECT_ERR_CNT)
- stats_print_redirect_err_cnt(cur, prev, nr_cpus);
-
- if (mask & SAMPLE_CPUMAP_ENQUEUE_CNT)
- stats_print_cpumap_enqueue(cur, prev, nr_cpus);
-
- if (mask & SAMPLE_CPUMAP_KTHREAD_CNT)
- stats_print_cpumap_kthread(cur, prev, nr_cpus);
+ stats_get_redirect_err_cnt(cur, prev, 0, &out);
if (mask & SAMPLE_EXCEPTION_CNT)
- stats_print_exception_cnt(cur, prev, nr_cpus);
+ stats_get_exception_cnt(cur, prev, 0, &out);
if (mask & SAMPLE_DEVMAP_XMIT_CNT)
- stats_print_devmap_xmit(cur, prev, nr_cpus);
+ stats_get_devmap_xmit(cur, prev, 0, &out);
+
+ stats_print(prog_name, mask, cur, prev, &out);
}
void sample_stats_poll(int interval, int mask, char *prog_name, int use_separators)
@@ -623,10 +821,10 @@ void sample_stats_poll(int interval, int mask, char *prog_name, int use_separato
for (;;) {
swap(&prev, &record);
sample_stats_collect(mask, record);
- sample_stats_print(mask, record, prev, NULL);
- printf("\n");
+ sample_stats_print(mask, record, prev, prog_name);
fflush(stdout);
sleep(interval);
+ sample_reset_mode();
}
free_stats_record(record);
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index bc0362575d4b..6ca934b346ef 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -44,10 +44,17 @@ static const char *const map_type_strings[] = {
[DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
};
+enum log_level {
+ LL_DEFAULT = 1U << 0,
+ LL_SIMPLE = 1U << 1,
+ LL_DEBUG = 1U << 2,
+};
+
extern struct bpf_link *tp_links[NUM_TP];
extern int map_fds[NUM_MAP];
extern int n_cpus;
extern int tp_cnt;
+extern enum log_level sample_log_level;
/* Exit return codes */
#define EXIT_OK 0
@@ -113,6 +120,34 @@ struct stats_record {
struct record enq[];
};
+struct sample_output {
+ struct {
+ __u64 rx;
+ __u64 redir;
+ __u64 drop;
+ __u64 err;
+ __u64 xmit;
+ } totals;
+ struct {
+ __u64 pps;
+ __u64 drop;
+ __u64 err;
+ } rx_cnt;
+ struct {
+ __u64 suc;
+ __u64 err;
+ } redir_cnt;
+ struct {
+ __u64 hits;
+ } except_cnt;
+ struct {
+ __u64 pps;
+ __u64 drop;
+ __u64 err;
+ double bavg;
+ } xmit_cnt;
+};
+
int sample_init(struct bpf_object *obj);
void sample_exit(int status);
struct stats_record *alloc_stats_record(void);
@@ -125,6 +160,7 @@ void sample_stats_poll(int interval, int mask, char *prog_name,
void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
struct stats_record *stats_prev,
unsigned int nr_cpus, char *mprog_name);
+void sample_reset_mode(void);
const char *get_driver_name(int ifindex);
int get_mac_addr(int ifindex, void *mac_addr);
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 11/15] samples: bpf: print summary of session on exit
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (9 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 10/15] samples: bpf: implement terse output mode and make it default Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 12/15] samples: bpf: subtract time spent in collection from polling interval Kumar Kartikeya Dwivedi
` (3 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This collects total statistics and prints the totals and averages for
main attributes when exiting. These are collected on each polling
interval.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_redirect_cpu_user.c | 2 +-
samples/bpf/xdp_redirect_map_user.c | 2 +-
samples/bpf/xdp_sample_user.c | 141 +++++++++++++++++++++++++---
samples/bpf/xdp_sample_user.h | 22 +++--
4 files changed, 145 insertions(+), 22 deletions(-)
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 3983ed71d879..4c9f32229508 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -216,7 +216,7 @@ static void __stats_poll(int interval, bool use_separators, char *prog_name,
for (;;) {
swap(&prev, &record);
sample_stats_collect(mask, record);
- sample_stats_print(mask, record, prev, NULL);
+ sample_stats_print(mask, record, prev, NULL, interval);
/* Depends on SAMPLE_CPUMAP_KTHREAD_CNT */
sample_stats_print_cpumap_remote(record, prev,
bpf_num_possible_cpus(),
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index b2c7adad99ec..ed53dd2cd93a 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -75,7 +75,7 @@ static void usage(const char *prog)
int main(int argc, char **argv)
{
- int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
+ int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT;
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index d0b26023f1db..909257ffe54c 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -26,8 +26,10 @@
#define SIOCETHTOOL 0x8946
#endif
+#include <fcntl.h>
#include <arpa/inet.h>
#include <linux/if_link.h>
+#include <sys/utsname.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
@@ -39,6 +41,7 @@ struct bpf_link *tp_links[NUM_TP] = {};
int map_fds[NUM_MAP], tp_cnt, n_cpus;
static int sample_sig_fd;
enum log_level sample_log_level = LL_SIMPLE;
+static struct sample_output sum_out;
static bool err_exp;
#define __sample_print(fmt, cond, printer, ...) \
@@ -58,6 +61,9 @@ static bool err_exp;
})
#define print_err(err, fmt, ...) __print_err(err, fmt, printf, ##__VA_ARGS__)
+#define print_link_err(err, str, width, type) \
+ __print_err(err, str, print_link, width, type)
+
#define __COLUMN(x) "%'10" x " %-13s"
#define FMT_COLUMNf __COLUMN(".0f")
#define FMT_COLUMNd __COLUMN("d")
@@ -71,6 +77,66 @@ static bool err_exp;
#define PASS(pass) pass, "pass/s"
#define REDIR(redir) redir, "redir/s"
+static const char *elixir_search[NUM_TP] = {
+ [TP_REDIRECT_CNT] = "_trace_xdp_redirect",
+ [TP_REDIRECT_MAP_CNT] = "_trace_xdp_redirect_map",
+ [TP_REDIRECT_ERR_CNT] = "_trace_xdp_redirect_err",
+ [TP_REDIRECT_MAP_ERR_CNT] = "_trace_xdp_redirect_map_err",
+ [TP_CPUMAP_ENQUEUE_CNT] = "trace_xdp_cpumap_enqueue",
+ [TP_CPUMAP_KTHREAD_CNT] = "trace_xdp_cpumap_kthread",
+ [TP_EXCEPTION_CNT] = "trace_xdp_exception",
+ [TP_DEVMAP_XMIT_CNT] = "trace_xdp_devmap_xmit",
+};
+
+static const char *make_url(enum tp_type i)
+{
+ const char *key = elixir_search[i];
+ static struct utsname uts = {};
+ static char url[128];
+ static bool uts_init;
+ int maj, min;
+ char c[2];
+
+ if (!uts_init) {
+ if (uname(&uts) < 0)
+ return NULL;
+ uts_init = true;
+ }
+
+ if (!key || sscanf(uts.release, "%d.%d%1s", &maj, &min, c) != 3)
+ return NULL;
+
+ snprintf(url, sizeof(url), "https://elixir.bootlin.com/linux/v%d.%d/C/ident/%s",
+ maj, min, key);
+
+ return url;
+}
+
+static void print_link(const char *str, int width, enum tp_type i)
+{
+ static int t = -1;
+ const char *s;
+ int fd, l;
+
+ if (t < 0) {
+ fd = open("/proc/self/fd/1", O_RDONLY);
+ if (fd < 0)
+ return;
+ t = isatty(fd);
+ close(fd);
+ }
+
+ s = make_url(i);
+ if (!s || !t) {
+ printf(" %-*s", width, str);
+ return;
+ }
+
+ l = strlen(str);
+ width = width - l > 0 ? width - l : 0;
+ printf(" \x1B]8;;%s\a%s\x1B]8;;\a%*c", s, str, width, ' ');
+}
+
#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
static __u64 gettime(void)
{
@@ -333,8 +399,11 @@ static void stats_get_cpumap_enqueue(struct stats_record *stats_rec,
if (err > 0)
err = pps / err; /* calc average bulk size */
- print_default(" %-20s " FMT_COLUMNf FMT_COLUMNf __COLUMN(".2f") "\n",
- str, PPS(pps), DROP(drop), err, "bulk_avg");
+
+ print_link_err(drop, str, 20, TP_CPUMAP_ENQUEUE_CNT);
+ print_err(drop,
+ " " FMT_COLUMNf FMT_COLUMNf __COLUMN(".2f") "\n",
+ PPS(pps), DROP(drop), err, "bulk_avg");
}
for (i = 0; i < nr_cpus; i++) {
@@ -375,8 +444,9 @@ static void stats_get_cpumap_kthread(struct stats_record *stats_rec,
drop = calc_drop_pps(&rec->total, &prev->total, t);
err = calc_errs_pps(&rec->total, &prev->total, t);
- print_default(" %-20s " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n", "kthread total",
- PPS(pps), DROP(drop), err, "sched");
+ print_link_err(drop, pps ? "kthread total" : "kthread", 20, TP_CPUMAP_KTHREAD_CNT);
+ print_err(drop, " " FMT_COLUMNf FMT_COLUMNf FMT_COLUMNf "\n",
+ PPS(pps), DROP(drop), err, "sched");
for (i = 0; i < nr_cpus; i++) {
struct datarec *r = &rec->cpu[i];
@@ -632,7 +702,9 @@ static void stats_print(const char *prefix, int mask, struct stats_record *r,
if (mask & SAMPLE_REDIRECT_CNT) {
str = out->redir_cnt.suc ? "redirect total" : "redirect";
- print_default(" %-20s " FMT_COLUMNl "\n", str, REDIR(out->redir_cnt.suc));
+ print_link_err(0, str, 20, mask & _SAMPLE_REDIRECT_MAP ?
+ TP_REDIRECT_MAP_CNT : TP_REDIRECT_CNT);
+ print_default(" " FMT_COLUMNl "\n", REDIR(out->redir_cnt.suc));
stats_get_redirect_cnt(r, p, nr_cpus, NULL);
}
@@ -640,6 +712,8 @@ static void stats_print(const char *prefix, int mask, struct stats_record *r,
if (mask & SAMPLE_REDIRECT_ERR_CNT) {
str = (sample_log_level & LL_DEFAULT) && out->redir_cnt.err ?
"redirect_err total" : "redirect_err";
+ print_link_err(out->redir_cnt.err, str, 20, mask & _SAMPLE_REDIRECT_MAP ?
+ TP_REDIRECT_MAP_ERR_CNT : TP_REDIRECT_ERR_CNT);
print_err(out->redir_cnt.err, " %-20s " FMT_COLUMNl "\n", str,
ERR(out->redir_cnt.err));
@@ -648,8 +722,9 @@ static void stats_print(const char *prefix, int mask, struct stats_record *r,
if (mask & SAMPLE_EXCEPTION_CNT) {
str = out->except_cnt.hits ? "xdp_exception total" : "xdp_exception";
- print_err(out->except_cnt.hits, " %-20s " FMT_COLUMNl "\n",
- str, HITS(out->except_cnt.hits));
+
+ print_link_err(out->except_cnt.hits, str, 20, TP_EXCEPTION_CNT);
+ print_err(out->except_cnt.hits, " " FMT_COLUMNl "\n", HITS(out->except_cnt.hits));
stats_get_exception_cnt(r, p, nr_cpus, NULL);
}
@@ -657,9 +732,11 @@ static void stats_print(const char *prefix, int mask, struct stats_record *r,
if (mask & SAMPLE_DEVMAP_XMIT_CNT) {
str = (sample_log_level & LL_DEFAULT) && out->xmit_cnt.pps ?
"devmap_xmit total" : "devmap_xmit";
+
+ print_link_err(out->xmit_cnt.err, str, 20, TP_DEVMAP_XMIT_CNT);
print_err(out->xmit_cnt.err,
- " %-20s " FMT_COLUMNl FMT_COLUMNl FMT_COLUMNl __COLUMN(".2f") "\n",
- str, XMIT(out->xmit_cnt.pps), DROP(out->xmit_cnt.drop),
+ " " FMT_COLUMNl FMT_COLUMNl FMT_COLUMNl __COLUMN(".2f") "\n",
+ XMIT(out->xmit_cnt.pps), DROP(out->xmit_cnt.drop),
out->xmit_cnt.err, "drv_err/s", out->xmit_cnt.bavg, "bulk_avg");
stats_get_devmap_xmit(r, p, nr_cpus, NULL);
@@ -747,7 +824,7 @@ void sample_exit(int status)
{
while (tp_cnt)
bpf_link__destroy(tp_links[--tp_cnt]);
-
+ sample_summary_print();
close(sample_sig_fd);
exit(status);
}
@@ -783,8 +860,46 @@ void sample_stats_collect(int mask, struct stats_record *rec)
map_collect_percpu(map_fds[DEVMAP_XMIT_CNT], 0, &rec->devmap_xmit);
}
+void sample_summary_update(struct sample_output *out, int interval)
+{
+ sum_out.totals.rx += out->totals.rx;
+ sum_out.totals.redir += out->totals.redir;
+ sum_out.totals.drop += out->totals.drop;
+ sum_out.totals.err += out->totals.err;
+ sum_out.totals.xmit += out->totals.xmit;
+ sum_out.rx_cnt.pps += interval;
+}
+
+void sample_summary_print(void)
+{
+ double period = sum_out.rx_cnt.pps;
+
+ print_always("\nTotals\n");
+ if (sum_out.totals.rx) {
+ double pkts = sum_out.totals.rx;
+
+ print_always(" Packets received : %'-10llu\n", sum_out.totals.rx);
+ print_always(" Average packets/s : %'-10.0f\n", sample_round(pkts/period));
+ }
+ if (sum_out.totals.redir) {
+ double pkts = sum_out.totals.redir;
+
+ print_always(" Packets redirected : %'-10llu\n", sum_out.totals.redir);
+ print_always(" Average redir/s : %'-10.0f\n", sample_round(pkts/period));
+ }
+ print_always(" Packets dropped : %'-10llu\n", sum_out.totals.drop);
+ print_always(" Errors recorded : %'-10llu\n", sum_out.totals.err);
+ if (sum_out.totals.xmit) {
+ double pkts = sum_out.totals.xmit;
+
+ print_always(" Packets transmitted : %'-10llu\n", sum_out.totals.xmit);
+ print_always(" Average transmit/s : %'-10.0f\n", sample_round(pkts/period));
+ }
+}
+
void sample_stats_print(int mask, struct stats_record *cur,
- struct stats_record *prev, char *prog_name)
+ struct stats_record *prev, char *prog_name,
+ int interval)
{
struct sample_output out = {};
@@ -803,6 +918,8 @@ void sample_stats_print(int mask, struct stats_record *cur,
if (mask & SAMPLE_DEVMAP_XMIT_CNT)
stats_get_devmap_xmit(cur, prev, 0, &out);
+ sample_summary_update(&out, interval);
+
stats_print(prog_name, mask, cur, prev, &out);
}
@@ -821,7 +938,7 @@ void sample_stats_poll(int interval, int mask, char *prog_name, int use_separato
for (;;) {
swap(&prev, &record);
sample_stats_collect(mask, record);
- sample_stats_print(mask, record, prev, prog_name);
+ sample_stats_print(mask, record, prev, prog_name, interval);
fflush(stdout);
sleep(interval);
sample_reset_mode();
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index 6ca934b346ef..abe4ec25c310 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -26,13 +26,16 @@ enum tp_type {
};
enum stats_mask {
- SAMPLE_RX_CNT = 1U << 1,
- SAMPLE_REDIRECT_ERR_CNT = 1U << 2,
- SAMPLE_CPUMAP_ENQUEUE_CNT = 1U << 3,
- SAMPLE_CPUMAP_KTHREAD_CNT = 1U << 4,
- SAMPLE_EXCEPTION_CNT = 1U << 5,
- SAMPLE_DEVMAP_XMIT_CNT = 1U << 6,
- SAMPLE_REDIRECT_CNT = 1U << 7,
+ _SAMPLE_REDIRECT_MAP = 1U << 0,
+ SAMPLE_RX_CNT = 1U << 1,
+ SAMPLE_REDIRECT_ERR_CNT = 1U << 2,
+ SAMPLE_CPUMAP_ENQUEUE_CNT = 1U << 3,
+ SAMPLE_CPUMAP_KTHREAD_CNT = 1U << 4,
+ SAMPLE_EXCEPTION_CNT = 1U << 5,
+ SAMPLE_DEVMAP_XMIT_CNT = 1U << 6,
+ SAMPLE_REDIRECT_CNT = 1U << 7,
+ SAMPLE_REDIRECT_MAP_CNT = SAMPLE_REDIRECT_CNT | _SAMPLE_REDIRECT_MAP,
+ SAMPLE_REDIRECT_ERR_MAP_CNT = SAMPLE_REDIRECT_ERR_CNT | _SAMPLE_REDIRECT_MAP,
};
static const char *const map_type_strings[] = {
@@ -153,8 +156,11 @@ void sample_exit(int status);
struct stats_record *alloc_stats_record(void);
void free_stats_record(struct stats_record *rec);
void sample_stats_print(int mask, struct stats_record *cur,
- struct stats_record *prev, char *prog_name);
+ struct stats_record *prev, char *prog_name,
+ int interval);
void sample_stats_collect(int mask, struct stats_record *rec);
+void sample_summary_update(struct sample_output *out, int interval);
+void sample_summary_print(void);
void sample_stats_poll(int interval, int mask, char *prog_name,
int use_separators);
void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 12/15] samples: bpf: subtract time spent in collection from polling interval
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (10 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 11/15] samples: bpf: print summary of session on exit Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 13/15] samples: bpf: add new options for xdp samples Kumar Kartikeya Dwivedi
` (2 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This improves sleeping precision and reduces the possibility of
reporting incorrect statistics to the user.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_redirect_cpu_user.c | 7 ++++++-
samples/bpf/xdp_sample_user.c | 27 ++++++++++++++++++++++++++-
samples/bpf/xdp_sample_user.h | 2 ++
3 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 4c9f32229508..103ac5c24163 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -214,6 +214,9 @@ static void __stats_poll(int interval, bool use_separators, char *prog_name,
setlocale(LC_NUMERIC, "en_US");
for (;;) {
+ struct timespec ots, nts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ots);
swap(&prev, &record);
sample_stats_collect(mask, record);
sample_stats_print(mask, record, prev, NULL, interval);
@@ -224,7 +227,9 @@ static void __stats_poll(int interval, bool use_separators, char *prog_name,
if (sample_log_level & LL_DEFAULT)
printf("\n");
fflush(stdout);
- sleep(interval);
+ clock_gettime(CLOCK_MONOTONIC, &nts);
+ sample_calc_timediff(&nts, &ots, interval);
+ nanosleep(&nts, NULL);
if (stress_mode)
stress_cpumap(value);
sample_reset_mode();
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index 909257ffe54c..96d36c708ee3 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -923,6 +923,26 @@ void sample_stats_print(int mask, struct stats_record *cur,
stats_print(prog_name, mask, cur, prev, &out);
}
+static void calc_timediff(struct timespec *cur, const struct timespec *prev)
+{
+ if (cur->tv_nsec - prev->tv_nsec < 0) {
+ cur->tv_sec = cur->tv_sec - prev->tv_sec - 1;
+ cur->tv_nsec = cur->tv_nsec - prev->tv_nsec + NANOSEC_PER_SEC;
+ } else {
+ cur->tv_sec -= prev->tv_sec;
+ cur->tv_nsec -= prev->tv_nsec;
+ }
+}
+
+void sample_calc_timediff(struct timespec *cur, const struct timespec *prev, int interval)
+{
+ struct timespec ts = { .tv_sec = interval };
+
+ calc_timediff(cur, prev);
+ calc_timediff(&ts, cur);
+ *cur = ts;
+}
+
void sample_stats_poll(int interval, int mask, char *prog_name, int use_separators)
{
struct stats_record *record, *prev;
@@ -936,11 +956,16 @@ void sample_stats_poll(int interval, int mask, char *prog_name, int use_separato
setlocale(LC_NUMERIC, "en_US");
for (;;) {
+ struct timespec ots, nts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ots);
swap(&prev, &record);
sample_stats_collect(mask, record);
sample_stats_print(mask, record, prev, prog_name, interval);
fflush(stdout);
- sleep(interval);
+ clock_gettime(CLOCK_MONOTONIC, &nts);
+ sample_calc_timediff(&nts, &ots, interval);
+ nanosleep(&nts, NULL);
sample_reset_mode();
}
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index abe4ec25c310..588bd2f15352 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -161,6 +161,8 @@ void sample_stats_print(int mask, struct stats_record *cur,
void sample_stats_collect(int mask, struct stats_record *rec);
void sample_summary_update(struct sample_output *out, int interval);
void sample_summary_print(void);
+void sample_calc_timediff(struct timespec *cur, const struct timespec *prev,
+ int interval);
void sample_stats_poll(int interval, int mask, char *prog_name,
int use_separators);
void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 13/15] samples: bpf: add new options for xdp samples
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (11 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 12/15] samples: bpf: subtract time spent in collection from polling interval Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 14/15] samples: bpf: add documentation Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 15/15] samples: bpf: convert xdp_samples to use raw_tracepoints Kumar Kartikeya Dwivedi
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
These are -i for polling interval and -v for verbose output by default.
Some of these tools already supported -s, but we now use that to enable
performance impacting success case reporting tracepoint. This is
disabled by default, but can be enabled explicitly by user.
Use separators (-z) is also dropped.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_monitor_user.c | 16 ++++---
samples/bpf/xdp_redirect_cpu_user.c | 41 ++++++++++++-----
samples/bpf/xdp_redirect_map_user.c | 71 +++++++++++++++++++++++------
3 files changed, 96 insertions(+), 32 deletions(-)
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index 73d6d35f0c65..b37d8f7379ec 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -38,9 +38,10 @@ struct bpf_object *obj;
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
{"debug", no_argument, NULL, 'D' },
- {"stats", no_argument, NULL, 'S' },
- {"sec", required_argument, NULL, 's' },
- {0, 0, NULL, 0 }
+ {"stats", no_argument, NULL, 's' },
+ {"interval", required_argument, NULL, 'i' },
+ {"verbose", no_argument, NULL, 'v' },
+ {}
};
static void int_exit(int sig)
@@ -121,18 +122,21 @@ int main(int argc, char **argv)
int interval = 2;
/* Parse commands line args */
- while ((opt = getopt_long(argc, argv, "hDSs:",
+ while ((opt = getopt_long(argc, argv, "hDi:vs",
long_options, &longindex)) != -1) {
switch (opt) {
case 'D':
debug = true;
break;
- case 'S':
+ case 's':
errors_only = false;
break;
- case 's':
+ case 'i':
interval = atoi(optarg);
break;
+ case 'v':
+ sample_log_level ^= LL_DEBUG - 1;
+ break;
case 'h':
default:
usage(argv);
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 103ac5c24163..d56b89254cd1 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -42,19 +42,20 @@ static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
{"dev", required_argument, NULL, 'd' },
{"skb-mode", no_argument, NULL, 'S' },
- {"sec", required_argument, NULL, 's' },
{"progname", required_argument, NULL, 'p' },
{"qsize", required_argument, NULL, 'q' },
{"cpu", required_argument, NULL, 'c' },
{"stress-mode", no_argument, NULL, 'x' },
- {"no-separators", no_argument, NULL, 'z' },
{"force", no_argument, NULL, 'F' },
{"mprog-disable", no_argument, NULL, 'n' },
{"mprog-name", required_argument, NULL, 'e' },
{"mprog-filename", required_argument, NULL, 'f' },
{"redirect-device", required_argument, NULL, 'r' },
{"redirect-map", required_argument, NULL, 'm' },
- {0, 0, NULL, 0 }
+ {"interval", required_argument, NULL, 'i' },
+ {"verbose", no_argument, NULL, 'v' },
+ {"stats", no_argument, NULL, 's' },
+ {}
};
static void int_exit(int sig)
@@ -196,7 +197,7 @@ static void stress_cpumap(struct bpf_cpumap_val *value)
create_cpu_entry(1, value, 0, false);
}
-static void __stats_poll(int interval, bool use_separators, char *prog_name,
+static void __stats_poll(int interval, bool redir_suc, char *prog_name,
char *mprog_name, struct bpf_cpumap_val *value,
bool stress_mode)
{
@@ -210,8 +211,10 @@ static void __stats_poll(int interval, bool use_separators, char *prog_name,
sample_stats_collect(mask, record);
/* Trick to pretty printf with thousands separators use %' */
- if (use_separators)
- setlocale(LC_NUMERIC, "en_US");
+ setlocale(LC_NUMERIC, "en_US");
+
+ if (redir_suc)
+ mask |= SAMPLE_REDIRECT_CNT;
for (;;) {
struct timespec ots, nts;
@@ -298,12 +301,12 @@ int main(int argc, char **argv)
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
struct bpf_cpumap_val value;
- bool use_separators = true;
bool stress_mode = false;
struct bpf_program *prog;
struct bpf_object *obj;
int err = EXIT_FAIL;
char filename[256];
+ bool redir = false;
int added_cpus = 0;
int longindex = 0;
int interval = 2;
@@ -356,7 +359,7 @@ int main(int argc, char **argv)
memset(cpu, 0, n_cpus * sizeof(int));
/* Parse commands line args */
- while ((opt = getopt_long(argc, argv, "hSd:s:p:q:c:xzFf:e:r:m:",
+ while ((opt = getopt_long(argc, argv, "hSd:sp:q:c:xi:vFf:e:r:m:",
long_options, &longindex)) != -1) {
switch (opt) {
case 'd':
@@ -375,6 +378,9 @@ int main(int argc, char **argv)
}
break;
case 's':
+ redir = true;
+ break;
+ case 'i':
interval = atoi(optarg);
break;
case 'S':
@@ -383,9 +389,6 @@ int main(int argc, char **argv)
case 'x':
stress_mode = true;
break;
- case 'z':
- use_separators = false;
- break;
case 'p':
/* Selecting eBPF prog to load */
prog_name = optarg;
@@ -422,6 +425,9 @@ int main(int argc, char **argv)
case 'F':
xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
break;
+ case 'v':
+ sample_log_level ^= LL_DEBUG - 1;
+ break;
case 'h':
error:
default:
@@ -492,7 +498,18 @@ int main(int argc, char **argv)
}
prog_id = info.id;
- __stats_poll(interval, use_separators, prog_name, mprog_name,
+ if (!redir) {
+ /* The bpf_link[i] depend on the order of
+ * the functions was defined in _kern.c
+ */
+ bpf_link__destroy(tp_links[2]); /* tracepoint/xdp/xdp_redirect */
+ tp_links[2] = NULL;
+
+ bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
+ tp_links[3] = NULL;
+ }
+
+ __stats_poll(interval, redir, prog_name, mprog_name,
&value, stress_mode);
err = EXIT_OK;
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index ed53dd2cd93a..eb4013fa58cb 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -13,6 +13,7 @@
#include <net/if.h>
#include <unistd.h>
#include <libgen.h>
+#include <getopt.h>
#include "bpf_util.h"
#include <bpf/bpf.h>
@@ -28,6 +29,18 @@ static __u32 dummy_prog_id;
static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+static const struct option long_options[] = {
+ {"help", no_argument, NULL, 'h' },
+ {"skb-mode", no_argument, NULL, 'S' },
+ {"native-mode", no_argument, NULL, 'N' },
+ {"force", no_argument, NULL, 'F' },
+ {"load-egress", no_argument, NULL, 'X' },
+ {"stats", no_argument, NULL, 's' },
+ {"interval", required_argument, NULL, 'i' },
+ {"verbose", no_argument, NULL, 'v' },
+ {}
+};
+
static void int_exit(int sig)
{
__u32 curr_prog_id = 0;
@@ -61,16 +74,25 @@ static void int_exit(int sig)
sample_exit(EXIT_OK);
}
-static void usage(const char *prog)
+static void usage(char *argv[])
{
- fprintf(stderr,
- "usage: %s [OPTS] <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n\n"
- "OPTS:\n"
- " -S use skb-mode\n"
- " -N enforce native mode\n"
- " -F force loading prog\n"
- " -X load xdp program on egress\n",
- prog);
+ int i;
+
+ printf("\n");
+ printf(" Usage: %s (options-see-below)\n",
+ argv[0]);
+ printf(" Listing options:\n");
+ for (i = 0; long_options[i].name != 0; i++) {
+ printf(" --%-15s", long_options[i].name);
+ if (long_options[i].flag != NULL)
+ printf(" flag (internal value:%d)",
+ *long_options[i].flag);
+ else
+ printf("short-option: -%c",
+ long_options[i].val);
+ printf("\n");
+ }
+ printf("\n");
}
int main(int argc, char **argv)
@@ -88,13 +110,14 @@ int main(int argc, char **argv)
char str[2 * IF_NAMESIZE + 1];
__u32 info_len = sizeof(info);
char ifname_out[IF_NAMESIZE];
- const char *optstr = "FSNX";
char ifname_in[IF_NAMESIZE];
struct bpf_object *obj;
int ret, opt, key = 0;
char filename[256];
+ int interval = 2;
- while ((opt = getopt(argc, argv, optstr)) != -1) {
+ while ((opt = getopt_long(argc, argv, "FSNXi:vs",
+ long_options, NULL)) != -1) {
switch (opt) {
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
@@ -108,8 +131,17 @@ int main(int argc, char **argv)
case 'X':
xdp_devmap_attached = true;
break;
+ case 'i':
+ interval = atoi(optarg);
+ break;
+ case 'v':
+ sample_log_level ^= LL_DEBUG - 1;
+ break;
+ case 's':
+ mask |= SAMPLE_REDIRECT_MAP_CNT;
+ break;
default:
- usage(basename(argv[0]));
+ usage(argv);
return 1;
}
}
@@ -122,7 +154,7 @@ int main(int argc, char **argv)
}
if (argc <= optind + 1) {
- usage(basename(argv[0]));
+ usage(argv);
return 1;
}
@@ -252,9 +284,20 @@ int main(int argc, char **argv)
ifname_in, ifindex_in, str, ifname_out, ifindex_out,
get_driver_name(ifindex_out) ?: "(err)");
+ if ((mask & SAMPLE_REDIRECT_CNT) == 0) {
+ /* The bpf_link[i] depend on the order of
+ * the functions was defined in _kern.c
+ */
+ bpf_link__destroy(tp_links[2]); /* tracepoint/xdp/xdp_redirect */
+ tp_links[2] = NULL;
+
+ bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
+ tp_links[3] = NULL;
+ }
+
snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
- sample_stats_poll(1, mask, str, true);
+ sample_stats_poll(interval, mask, str, true);
return 0;
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 14/15] samples: bpf: add documentation
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (12 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 13/15] samples: bpf: add new options for xdp samples Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-28 23:52 ` [PATCH RFC bpf-next 15/15] samples: bpf: convert xdp_samples to use raw_tracepoints Kumar Kartikeya Dwivedi
14 siblings, 0 replies; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
This prints some help text meant to explain the output.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_monitor_user.c | 10 ++++--
samples/bpf/xdp_redirect_cpu_user.c | 8 +++--
samples/bpf/xdp_redirect_map_user.c | 6 ++--
samples/bpf/xdp_sample_user.c | 52 +++++++++++++++++++++++++++++
samples/bpf/xdp_sample_user.h | 1 +
5 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index b37d8f7379ec..71d59e714bae 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -35,6 +35,10 @@ static const char *__doc_err_only__=
static bool debug = false;
struct bpf_object *obj;
+static int mask = SAMPLE_REDIRECT_ERR_CNT | SAMPLE_CPUMAP_ENQUEUE_CNT |
+ SAMPLE_CPUMAP_KTHREAD_CNT | SAMPLE_EXCEPTION_CNT |
+ SAMPLE_DEVMAP_XMIT_CNT;
+
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
{"debug", no_argument, NULL, 'D' },
@@ -56,6 +60,9 @@ static void int_exit(int sig)
static void usage(char *argv[])
{
int i;
+
+ sample_print_help(mask);
+
printf("\nDOCUMENTATION:\n%s\n", __doc__);
printf("\n");
printf(" Usage: %s (options-see-below)\n",
@@ -110,9 +117,6 @@ static void print_bpf_prog_info(void)
int main(int argc, char **argv)
{
- int mask = SAMPLE_REDIRECT_ERR_CNT | SAMPLE_CPUMAP_ENQUEUE_CNT |
- SAMPLE_CPUMAP_KTHREAD_CNT | SAMPLE_EXCEPTION_CNT |
- SAMPLE_DEVMAP_XMIT_CNT;
int longindex = 0, opt;
int ret = EXIT_FAILURE;
char filename[256];
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index d56b89254cd1..9233b8a2bf2d 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -37,6 +37,9 @@ static int avail_fd;
static int count_fd;
static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
+ SAMPLE_CPUMAP_ENQUEUE_CNT | SAMPLE_CPUMAP_KTHREAD_CNT |
+ SAMPLE_EXCEPTION_CNT;
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
@@ -96,6 +99,8 @@ static void usage(char *argv[], struct bpf_object *obj)
{
int i;
+ sample_print_help(mask);
+
printf("\nDOCUMENTATION:\n%s\n", __doc__);
printf("\n");
printf(" Usage: %s (options-see-below)\n", argv[0]);
@@ -201,9 +206,6 @@ static void __stats_poll(int interval, bool redir_suc, char *prog_name,
char *mprog_name, struct bpf_cpumap_val *value,
bool stress_mode)
{
- int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
- SAMPLE_CPUMAP_ENQUEUE_CNT | SAMPLE_CPUMAP_KTHREAD_CNT |
- SAMPLE_EXCEPTION_CNT;
struct stats_record *record, *prev;
record = alloc_stats_record();
diff --git a/samples/bpf/xdp_redirect_map_user.c b/samples/bpf/xdp_redirect_map_user.c
index eb4013fa58cb..f4bdefa83709 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -28,6 +28,8 @@ static __u32 prog_id;
static __u32 dummy_prog_id;
static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
+ SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT;
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
@@ -78,6 +80,8 @@ static void usage(char *argv[])
{
int i;
+ sample_print_help(mask);
+
printf("\n");
printf(" Usage: %s (options-see-below)\n",
argv[0]);
@@ -97,8 +101,6 @@ static void usage(char *argv[])
int main(int argc, char **argv)
{
- int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
- SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT;
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
};
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index 96d36c708ee3..aa02d9bbea6c 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -77,6 +77,58 @@ static bool err_exp;
#define PASS(pass) pass, "pass/s"
#define REDIR(redir) redir, "redir/s"
+void sample_print_help(int mask)
+{
+ printf("Output format description\n\n"
+ "By default, redirect success statistics are disabled, use -s to enable.\n"
+ "The terse output mode is default, verbose mode can be activated using -v\n"
+ "Use SIGQUIT (Ctrl + \\) to switch the mode dynamically at runtime\n\n"
+ "Terse mode displays at most the following fields:\n"
+ " rx/s Number of packets received per second\n"
+ " redir/s Number of packets successfully redirected per second\n"
+ " error/s Aggregated count of errors per second (including dropped packets)\n"
+ " xmit/s Number of packets transmitted on the output device per second\n\n"
+ "Output description for verbose mode:\n"
+ " FIELD DESCRIPTION\n");
+ if (mask & SAMPLE_RX_CNT) {
+ printf(" receive\tDisplays the number of packets received & errors encountered\n"
+ " \t\tWhenever an error or packet drop occurs, details of per CPU error\n"
+ " \t\tand drop statistics will be expanded inline in terse mode.\n"
+ " \t\t\tpkt/s - Packets received per second\n"
+ " \t\t\tdrop/s - Packets dropped per second\n"
+ " \t\t\terror/s - Errors encountered per second\n\n");
+ }
+ if (mask & (SAMPLE_REDIRECT_CNT|SAMPLE_REDIRECT_ERR_CNT)) {
+ printf(" redirect\tDisplays the number of packets successfully redirected\n"
+ " \t\tErrors encountered are expanded under redirect_err field\n"
+ " \t\tNote that passing -s to enable it has a per packet overhead\n"
+ " \t\t\tredir/s - Packets redirected successfully per second\n\n"
+ " redirect_err\tDisplays the number of packets that failed redirection\n"
+ " \t\tThe errno is expanded under this field with per CPU count\n"
+ " \t\tThe recognized errors are EOPNOTSUPP, EINVAL, ENETDOWN and EMSGSIZE\n"
+ " \t\t\terror/s - Packets that failed redirection per second\n\n");
+ }
+
+ if (mask & SAMPLE_EXCEPTION_CNT) {
+ printf(" xdp_exception\tDisplays xdp_exception tracepoint events\n"
+ " \t\tThis can occur due to internal driver errors, unrecognized\n"
+ " \t\tXDP actions and due to explicit user trigger by use of XDP_ABORTED\n"
+ " \t\tEach action is expanded below this field with its count\n"
+ " \t\t\thit/s - Number of times the tracepoint was hit per second\n\n");
+ }
+
+ if (mask & SAMPLE_DEVMAP_XMIT_CNT) {
+ printf(" devmap_xmit\tDisplays devmap_xmit tracepoint events\n"
+ " \t\tThis tracepoint is invoked for successful transmissions on output\n"
+ " \t\tdevice but these statistics are not available for generic XDP mode,\n"
+ " \t\thence they will be omitted from the output when using SKB mode\n"
+ " \t\t\txmit/s - Number of packets that were transmitted per second\n"
+ " \t\t\tdrop/s - Number of packets that failed transmissions per second\n"
+ " \t\t\tdrv_err/s - Number of internal driver errors per second\n"
+ " \t\t\tbulk_avg - Average number of packets processed for each event\n\n");
+ }
+}
+
static const char *elixir_search[NUM_TP] = {
[TP_REDIRECT_CNT] = "_trace_xdp_redirect",
[TP_REDIRECT_MAP_CNT] = "_trace_xdp_redirect_map",
diff --git a/samples/bpf/xdp_sample_user.h b/samples/bpf/xdp_sample_user.h
index 588bd2f15352..41be57d7b663 100644
--- a/samples/bpf/xdp_sample_user.h
+++ b/samples/bpf/xdp_sample_user.h
@@ -169,6 +169,7 @@ void sample_stats_print_cpumap_remote(struct stats_record *stats_rec,
struct stats_record *stats_prev,
unsigned int nr_cpus, char *mprog_name);
void sample_reset_mode(void);
+void sample_print_help(int mask);
const char *get_driver_name(int ifindex);
int get_mac_addr(int ifindex, void *mac_addr);
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH RFC bpf-next 15/15] samples: bpf: convert xdp_samples to use raw_tracepoints
2021-05-28 23:52 [PATCH RFC bpf-next 00/15] Improve XDP samples usability and output Kumar Kartikeya Dwivedi
` (13 preceding siblings ...)
2021-05-28 23:52 ` [PATCH RFC bpf-next 14/15] samples: bpf: add documentation Kumar Kartikeya Dwivedi
@ 2021-05-28 23:52 ` Kumar Kartikeya Dwivedi
2021-05-30 3:07 ` Andrii Nakryiko
14 siblings, 1 reply; 18+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2021-05-28 23:52 UTC (permalink / raw)
To: bpf
Cc: Kumar Kartikeya Dwivedi, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen, netdev
These are faster, and hence speeds up cases where user passes --stats to
enable success case redirect accounting. We can extend this to all other
tracepoints as well, so make that part of this change.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
samples/bpf/xdp_sample_kern.h | 145 +++++++++++-----------------------
samples/bpf/xdp_sample_user.c | 2 +-
2 files changed, 45 insertions(+), 102 deletions(-)
diff --git a/samples/bpf/xdp_sample_kern.h b/samples/bpf/xdp_sample_kern.h
index dd7f7ea63166..08fbc55df3fd 100644
--- a/samples/bpf/xdp_sample_kern.h
+++ b/samples/bpf/xdp_sample_kern.h
@@ -3,6 +3,9 @@
#pragma once
#include <uapi/linux/bpf.h>
+#include <net/xdp.h>
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#ifndef NR_CPUS
@@ -85,20 +88,6 @@ struct {
/*** Trace point code ***/
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_redirect_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12 size:4; signed:0;
- int ifindex; // offset:16 size:4; signed:1;
- int err; // offset:20 size:4; signed:1;
- int to_ifindex; // offset:24 size:4; signed:1;
- u32 map_id; // offset:28 size:4; signed:0;
- int map_index; // offset:32 size:4; signed:1;
-}; // offset:36
-
enum {
XDP_REDIRECT_SUCCESS = 0,
XDP_REDIRECT_ERROR = 1
@@ -124,11 +113,11 @@ __u32 xdp_get_err_key(int err)
}
static __always_inline
-int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
+int xdp_redirect_collect_stat(struct bpf_raw_tracepoint_args *ctx)
{
u32 key = XDP_REDIRECT_ERROR;
+ int err = ctx->args[3];
struct datarec *rec;
- int err = ctx->err;
key = xdp_get_err_key(err);
@@ -149,47 +138,35 @@ int xdp_redirect_collect_stat(struct xdp_redirect_ctx *ctx)
*/
}
-SEC("tracepoint/xdp/xdp_redirect_err")
-int trace_xdp_redirect_err(struct xdp_redirect_ctx *ctx)
+SEC("raw_tracepoint/xdp_redirect_err")
+int trace_xdp_redirect_err(struct bpf_raw_tracepoint_args *ctx)
{
return xdp_redirect_collect_stat(ctx);
}
-SEC("tracepoint/xdp/xdp_redirect_map_err")
-int trace_xdp_redirect_map_err(struct xdp_redirect_ctx *ctx)
+SEC("raw_tracepoint/xdp_redirect_map_err")
+int trace_xdp_redirect_map_err(struct bpf_raw_tracepoint_args *ctx)
{
return xdp_redirect_collect_stat(ctx);
}
-/* Likely unloaded when prog starts */
-SEC("tracepoint/xdp/xdp_redirect")
-int trace_xdp_redirect(struct xdp_redirect_ctx *ctx)
+SEC("raw_tracepoint/xdp_redirect")
+int trace_xdp_redirect(struct bpf_raw_tracepoint_args *ctx)
{
return xdp_redirect_collect_stat(ctx);
}
-/* Likely unloaded when prog starts */
-SEC("tracepoint/xdp/xdp_redirect_map")
-int trace_xdp_redirect_map(struct xdp_redirect_ctx *ctx)
+SEC("raw_tracepoint/xdp_redirect_map")
+int trace_xdp_redirect_map(struct bpf_raw_tracepoint_args *ctx)
{
return xdp_redirect_collect_stat(ctx);
}
-/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct xdp_exception_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int prog_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int ifindex; // offset:16; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_exception")
-int trace_xdp_exception(struct xdp_exception_ctx *ctx)
+SEC("raw_tracepoint/xdp_exception")
+int trace_xdp_exception(struct bpf_raw_tracepoint_args *ctx)
{
+ u32 key = ctx->args[2];
struct datarec *rec;
- u32 key = ctx->act;
if (key > XDP_REDIRECT)
key = XDP_UNKNOWN;
@@ -202,23 +179,10 @@ int trace_xdp_exception(struct xdp_exception_ctx *ctx)
return 0;
}
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_enqueue_ctx {
- u64 __pad; // First 8 bytes are not accessible by bpf code
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int to_cpu; // offset:28; size:4; signed:1;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_enqueue")
-int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
+SEC("raw_tracepoint/xdp_cpumap_enqueue")
+int trace_xdp_cpumap_enqueue(struct bpf_raw_tracepoint_args *ctx)
{
- u32 to_cpu = ctx->to_cpu;
+ u32 to_cpu = ctx->args[3];
struct datarec *rec;
if (to_cpu >= MAX_CPUS)
@@ -227,11 +191,11 @@ int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &to_cpu);
if (!rec)
return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
+ rec->processed += ctx->args[1];
+ rec->dropped += ctx->args[2];
/* Record bulk events, then userspace can calc average bulk size */
- if (ctx->processed > 0)
+ if (ctx->args[1] > 0)
rec->issue += 1;
/* Inception: It's possible to detect overload situations, via
@@ -242,78 +206,57 @@ int trace_xdp_cpumap_enqueue(struct cpumap_enqueue_ctx *ctx)
return 0;
}
-/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_kthread/format
- * Code in: kernel/include/trace/events/xdp.h
- */
-struct cpumap_kthread_ctx {
- u64 __pad; // First 8 bytes are not accessible
- int map_id; // offset:8; size:4; signed:1;
- u32 act; // offset:12; size:4; signed:0;
- int cpu; // offset:16; size:4; signed:1;
- unsigned int drops; // offset:20; size:4; signed:0;
- unsigned int processed; // offset:24; size:4; signed:0;
- int sched; // offset:28; size:4; signed:1;
- unsigned int xdp_pass; // offset:32; size:4; signed:0;
- unsigned int xdp_drop; // offset:36; size:4; signed:0;
- unsigned int xdp_redirect; // offset:40; size:4; signed:0;
-};
-
-SEC("tracepoint/xdp/xdp_cpumap_kthread")
-int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx)
+SEC("raw_tracepoint/xdp_cpumap_kthread")
+int trace_xdp_cpumap_kthread(struct bpf_raw_tracepoint_args *ctx)
{
+ struct xdp_cpumap_stats *stats;
struct datarec *rec;
u32 key = 0;
+ stats = (struct xdp_cpumap_stats *) ctx->args[4];
+ if (!stats)
+ return 0;
+
rec = bpf_map_lookup_elem(&cpumap_kthread_cnt, &key);
if (!rec)
return 0;
- rec->processed += ctx->processed;
- rec->dropped += ctx->drops;
- rec->xdp_pass += ctx->xdp_pass;
- rec->xdp_drop += ctx->xdp_drop;
- rec->xdp_redirect += ctx->xdp_redirect;
+ rec->processed += ctx->args[1];
+ rec->dropped += ctx->args[2];
+
+ rec->xdp_pass += BPF_CORE_READ(stats, pass);
+ rec->xdp_drop += BPF_CORE_READ(stats, drop);
+ rec->xdp_redirect += BPF_CORE_READ(stats, redirect);
/* Count times kthread yielded CPU via schedule call */
- if (ctx->sched)
+ if (ctx->args[3])
rec->issue++;
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)
+SEC("raw_tracepoint/xdp_devmap_xmit")
+int trace_xdp_devmap_xmit(struct bpf_raw_tracepoint_args *ctx)
{
struct datarec *rec;
u32 key = 0;
+ int drops;
rec = bpf_map_lookup_elem(&devmap_xmit_cnt, &key);
if (!rec)
return 0;
- rec->processed += ctx->sent;
- rec->dropped += ctx->drops;
+ rec->processed += ctx->args[2];
+ rec->dropped += ctx->args[3];
/* Record bulk events, then userspace can calc average bulk size */
rec->info += 1;
/* Record error cases, where no frame were sent */
- if (ctx->err)
+ if (ctx->args[4])
rec->issue++;
+ drops = ctx->args[3];
/* Catch API error of drv ndo_xdp_xmit sent more than count */
- if (ctx->drops < 0)
+ if (drops < 0)
rec->issue++;
return 1;
diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
index aa02d9bbea6c..539c0c78fcb0 100644
--- a/samples/bpf/xdp_sample_user.c
+++ b/samples/bpf/xdp_sample_user.c
@@ -805,7 +805,7 @@ static int init_tracepoints(struct bpf_object *obj)
struct bpf_program *prog;
bpf_object__for_each_program(prog, obj) {
- if (bpf_program__is_tracepoint(prog) != true)
+ if (!bpf_program__is_raw_tracepoint(prog))
continue;
tp_links[tp_cnt] = bpf_program__attach(prog);
--
2.31.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH RFC bpf-next 15/15] samples: bpf: convert xdp_samples to use raw_tracepoints
2021-05-28 23:52 ` [PATCH RFC bpf-next 15/15] samples: bpf: convert xdp_samples to use raw_tracepoints Kumar Kartikeya Dwivedi
@ 2021-05-30 3:07 ` Andrii Nakryiko
0 siblings, 0 replies; 18+ messages in thread
From: Andrii Nakryiko @ 2021-05-30 3:07 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, David S. Miller, Jakub Kicinski,
Jesper Dangaard Brouer, Toke Høiland-Jørgensen,
Networking
On Fri, May 28, 2021 at 4:54 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> These are faster, and hence speeds up cases where user passes --stats to
> enable success case redirect accounting. We can extend this to all other
> tracepoints as well, so make that part of this change.
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
> samples/bpf/xdp_sample_kern.h | 145 +++++++++++-----------------------
> samples/bpf/xdp_sample_user.c | 2 +-
> 2 files changed, 45 insertions(+), 102 deletions(-)
>
[...]
>
> -/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_exception/format
> - * Code in: kernel/include/trace/events/xdp.h
> - */
> -struct xdp_exception_ctx {
> - u64 __pad; // First 8 bytes are not accessible by bpf code
> - int prog_id; // offset:8; size:4; signed:1;
> - u32 act; // offset:12; size:4; signed:0;
> - int ifindex; // offset:16; size:4; signed:1;
> -};
> -
> -SEC("tracepoint/xdp/xdp_exception")
> -int trace_xdp_exception(struct xdp_exception_ctx *ctx)
> +SEC("raw_tracepoint/xdp_exception")
> +int trace_xdp_exception(struct bpf_raw_tracepoint_args *ctx)
> {
check out use of BPF_PROG macro for raw_tracepoint and fentry/fexit
programs, it looks nicer, IMO.
> + u32 key = ctx->args[2];
> struct datarec *rec;
> - u32 key = ctx->act;
>
> if (key > XDP_REDIRECT)
> key = XDP_UNKNOWN;
[...]
^ permalink raw reply [flat|nested] 18+ messages in thread