Skip to contentSkip to conversation

perf, bpf: add support for bpf in sw/hw perf_events

PATCH Superseded Alexei Starovoitov 5 participants 13 messages Aug 31, 2016 – Sep 1, 2016

Subsystems (8)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover perf, bpf: add support for bpf in sw/hw perf_events

Hi Peter, Dave,

this patch set is a follow up to the discussion:
https://lkml.kernel.org/r/20160804142853.GO6862%20()%20twins%20!%20programming%20!%20kicks-ass%20!%20net
It turned out to be simpler than what we discussed.

Patches 1-3 is bpf-side prep for the main patch 4
that adds bpf program as an overflow_handler to sw and hw perf_events. Peter, please review.

Patches 5 and 6 are examples from myself and Brendan.

v1-v2: fixed issues spotted by Peter and Daniel.

Thanks!

Alexei Starovoitov (5):
bpf: support 8-byte metafield access
bpf: introduce BPF_PROG_TYPE_PERF_EVENT program type
bpf: perf_event progs should only use preallocated maps perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT
programs
samples/bpf: add perf_event+bpf example

Brendan Gregg (1):
samples/bpf: add sampleip example

 include/linux/bpf.h                 |   4 +
 include/linux/perf_event.h          |   7 ++
 include/uapi/linux/Kbuild           |   1 +
 include/uapi/linux/bpf.h            |   1 +
 include/uapi/linux/bpf_perf_event.h |  18 +++
 kernel/bpf/verifier.c               |  31 +++++-
 kernel/events/core.c                |  85 +++++++++++++-
 kernel/trace/bpf_trace.c            |  60 ++++++++++
 samples/bpf/Makefile                |   8 ++
 samples/bpf/bpf_helpers.h           |   2 +
 samples/bpf/bpf_load.c              |   7 +-
 samples/bpf/sampleip_kern.c         |  38 +++++++
 samples/bpf/sampleip_user.c         | 196 +++++++++++++++++++++++++++++++++
 samples/bpf/trace_event_kern.c      |  65 +++++++++++
 samples/bpf/trace_event_user.c      | 213 ++++++++++++++++++++++++++++++++++++
 15 files changed, 730 insertions(+), 6 deletions(-)
 create mode 100644 include/uapi/linux/bpf_perf_event.h
 create mode 100644 samples/bpf/sampleip_kern.c
 create mode 100644 samples/bpf/sampleip_user.c
 create mode 100644 samples/bpf/trace_event_kern.c
 create mode 100644 samples/bpf/trace_event_user.c
Signature · 1 line
2.8.0
#1 lore raw

PATCH v2 1/6 bpf: support 8-byte metafield access

The verifier supported only 4-byte metafields in
struct __sk_buff and struct xdp_md. The metafields in upcoming struct bpf_perf_event are 8-byte to match register width in struct pt_regs. Teach verifier to recognize 8-byte metafield access.
The patch doesn't affect safety of sockets and xdp programs. They check for 4-byte only ctx access before these conditions are hit.

---
 kernel/bpf/verifier.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
kernel/bpf/verifier.c +6 -3
index abb61f3f6900..c1c9e441f0f5 100644
@@ -2333,7 +2333,8 @@ static int do_check(struct verifier_env *env)
 			if (err)
 				return err;
 
-			if (BPF_SIZE(insn->code) != BPF_W) {
+			if (BPF_SIZE(insn->code) != BPF_W &&
+			    BPF_SIZE(insn->code) != BPF_DW) {
 				insn_idx++;
 				continue;
 			}
@@ -2642,9 +2643,11 @@ static int convert_ctx_accesses(struct verifier_env *env)
 	for (i = 0; i < insn_cnt; i++, insn++) {
 		u32 insn_delta, cnt;
 
-		if (insn->code == (BPF_LDX | BPF_MEM | BPF_W))
+		if (insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
+		    insn->code == (BPF_LDX | BPF_MEM | BPF_DW))
 			type = BPF_READ;
-		else if (insn->code == (BPF_STX | BPF_MEM | BPF_W))
+		else if (insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
+			 insn->code == (BPF_STX | BPF_MEM | BPF_DW))
 			type = BPF_WRITE;
 		else
 			continue;
Signature · 1 line
2.8.0
#2 lore raw

PATCH v2 2/6 bpf: introduce BPF_PROG_TYPE_PERF_EVENT program type

In reply to Alexei Starovoitov

Introduce BPF_PROG_TYPE_PERF_EVENT programs that can be attached to HW and SW perf events (PERF_TYPE_HARDWARE and PERF_TYPE_SOFTWARE correspondingly in uapi/linux/perf_event.h)

The program visible context meta structure is

struct bpf_perf_event_data {
    struct pt_regs regs;
     __u64 sample_period;
};

which is accessible directly from the program:
int bpf_prog(struct bpf_perf_event_data *ctx)
{
... ctx->sample_period ...
... ctx->regs.ip ...
}

The bpf verifier rewrites the accesses into kernel internal struct bpf_perf_event_data_kern which allows changing struct perf_sample_data without affecting bpf programs. New fields can be added to the end of struct bpf_perf_event_data in the future.

---
 include/linux/perf_event.h          |  5 ++++
 include/uapi/linux/Kbuild           |  1 +
 include/uapi/linux/bpf.h            |  1 +
 include/uapi/linux/bpf_perf_event.h | 18 +++++++++++
 kernel/trace/bpf_trace.c            | 60 +++++++++++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+)
 create mode 100644 include/uapi/linux/bpf_perf_event.h
include/linux/perf_event.h +5 -0
index 2b6b43cc0dd5..97bfe62f30d7 100644
@@ -788,6 +788,11 @@ struct perf_output_handle {
 	int				page;
 };
 
+struct bpf_perf_event_data_kern {
+	struct pt_regs *regs;
+	struct perf_sample_data *data;
+};
+
 #ifdef CONFIG_CGROUP_PERF
 
 /*
include/uapi/linux/Kbuild +1 -0
index 185f8ea2702f..d0352a971ebd 100644
@@ -71,6 +71,7 @@ header-y += binfmts.h
 header-y += blkpg.h
 header-y += blktrace_api.h
 header-y += bpf_common.h
+header-y += bpf_perf_event.h
 header-y += bpf.h
 header-y += bpqether.h
 header-y += bsg.h
include/uapi/linux/bpf.h +1 -0
index e4c5a1baa993..f896dfac4ac0 100644
@@ -95,6 +95,7 @@ enum bpf_prog_type {
 	BPF_PROG_TYPE_SCHED_ACT,
 	BPF_PROG_TYPE_TRACEPOINT,
 	BPF_PROG_TYPE_XDP,
+	BPF_PROG_TYPE_PERF_EVENT,
 };
 
 #define BPF_PSEUDO_MAP_FD	1
include/uapi/linux/bpf_perf_event.h new file +18 -0
new file mode 100644
index 000000000000..067427259820
@@ -0,0 +1,18 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef _UAPI__LINUX_BPF_PERF_EVENT_H__
+#define _UAPI__LINUX_BPF_PERF_EVENT_H__
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+struct bpf_perf_event_data {
+	struct pt_regs regs;
+	__u64 sample_period;
+};
+
+#endif /* _UAPI__LINUX_BPF_PERF_EVENT_H__ */
kernel/trace/bpf_trace.c +60 -0

80 lines not on this page · raw message

Signature · 1 line
2.8.0
maintainer
#3 lore raw

Re: [PATCH v2 net-next 2/6] bpf: introduce BPF_PROG_TYPE_PERF_EVENT program type

Quoted 6 lines · Alexei Starovoitov
kernel/trace/bpf_trace.c +6 -0
+static u32 pe_prog_convert_ctx_access(enum bpf_access_type type, int dst_reg,
+				      int src_reg, int ctx_off,
+				      struct bpf_insn *insn_buf,
+				      struct bpf_prog *prog)
+{
+	struct bpf_insn *insn = insn_buf;

kernel/trace/bpf_trace.c static struct bpf_prog_type_list tracepoint_tl = { · line 591

Quoted 10 lines
kernel/trace/bpf_trace.c +10 -0
+
+	BUILD_BUG_ON(FIELD_SIZEOF(struct perf_sample_data, period) != sizeof(u64));
+	switch (ctx_off) {
+	case offsetof(struct bpf_perf_event_data, sample_period):
+		*insn++ = BPF_LDX_MEM(bytes_to_bpf_size(FIELD_SIZEOF(struct bpf_perf_event_data_kern, data)),
+				      dst_reg, src_reg,
+				      offsetof(struct bpf_perf_event_data_kern, data));
+		*insn++ = BPF_LDX_MEM(BPF_DW, dst_reg, dst_reg,
+				      offsetof(struct perf_sample_data, period));
+		break;

OK, so that deals with us moving the period field in the structure, and break compile if we'd change its size or remove it outright (highly unlikely). In that latter case we can change this code to simply return a (u64)0 and things would continue to 'work'.

Did I understand that correctly?

maintainer
#4 lore raw

Re: [PATCH v2 net-next 2/6] bpf: introduce BPF_PROG_TYPE_PERF_EVENT program type

Quoted 23 lines · Peter Zijlstra
Quoted 6 lines · Alexei Starovoitov
kernel/trace/bpf_trace.c +6 -0
+static u32 pe_prog_convert_ctx_access(enum bpf_access_type type, int dst_reg,
+				      int src_reg, int ctx_off,
+				      struct bpf_insn *insn_buf,
+				      struct bpf_prog *prog)
+{
+	struct bpf_insn *insn = insn_buf;

kernel/trace/bpf_trace.c static struct bpf_prog_type_list tracepoint_tl = { · line 591

Quoted 10 lines
kernel/trace/bpf_trace.c +10 -0
+
+	BUILD_BUG_ON(FIELD_SIZEOF(struct perf_sample_data, period) != sizeof(u64));
+	switch (ctx_off) {
+	case offsetof(struct bpf_perf_event_data, sample_period):
+		*insn++ = BPF_LDX_MEM(bytes_to_bpf_size(FIELD_SIZEOF(struct bpf_perf_event_data_kern, data)),
+				      dst_reg, src_reg,
+				      offsetof(struct bpf_perf_event_data_kern, data));
+		*insn++ = BPF_LDX_MEM(BPF_DW, dst_reg, dst_reg,
+				      offsetof(struct perf_sample_data, period));
+		break;

OK, so that deals with us moving the period field in the structure, and break compile if we'd change its size or remove it outright (highly unlikely). In that latter case we can change this code to simply return a (u64)0 and things would continue to 'work'.

Quoted 1 line

Did I understand that correctly?

Yes, if a program accesses sample_period member of the struct bpf_perf_event_data context, then the verifier rewrites this into above two loads to eventually fetch the struct perf_sample_data's period to the given target register. As you said, should the period field change size (or get removed), compilation would break so this doesn't get unnoticed and the code can be adapted along with it. In the (hopefully very unlikely) case the member gets removed, it could be replaced with loading 0 (or some other, better workaround to derive it, if possible).

#5 lore raw

PATCH v2 3/6 bpf: perf_event progs should only use preallocated maps

In reply to Alexei Starovoitov

Make sure that BPF_PROG_TYPE_PERF_EVENT programs only use preallocated hash maps, since doing memory allocation
in overflow_handler can crash depending on where nmi got triggered.

---
 kernel/bpf/verifier.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
kernel/bpf/verifier.c +21 -1
index c1c9e441f0f5..48c2705db22c 100644
@@ -2511,6 +2511,20 @@ process_bpf_exit:
 	return 0;
 }
 
+static int check_map_prog_compatibility(struct bpf_map *map,
+					struct bpf_prog *prog)
+
+{
+	if (prog->type == BPF_PROG_TYPE_PERF_EVENT &&
+	    (map->map_type == BPF_MAP_TYPE_HASH ||
+	     map->map_type == BPF_MAP_TYPE_PERCPU_HASH) &&
+	    (map->map_flags & BPF_F_NO_PREALLOC)) {
+		verbose("perf_event programs can only use preallocated hash map\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 /* look for pseudo eBPF instructions that access map FDs and
  * replace them with actual map pointers
  */
@@ -2518,7 +2532,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
 {
 	struct bpf_insn *insn = env->prog->insnsi;
 	int insn_cnt = env->prog->len;
-	int i, j;
+	int i, j, err;
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
 		if (BPF_CLASS(insn->code) == BPF_LDX &&
@@ -2562,6 +2576,12 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
 				return PTR_ERR(map);
 			}
 
+			err = check_map_prog_compatibility(map, env->prog);
+			if (err) {
+				fdput(f);
+				return err;
+			}
+
 			/* store map pointer inside BPF_LD_IMM64 instruction */
 			insn[0].imm = (u32) (unsigned long) map;
 			insn[1].imm = ((u64) (unsigned long) map) >> 32;
Signature · 1 line
2.8.0
#6 lore raw

PATCH v2 4/6 perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT programs

In reply to Alexei Starovoitov

Allow attaching BPF_PROG_TYPE_PERF_EVENT programs to sw and hw perf events via overflow_handler mechanism.
When program is attached the overflow_handlers become stacked.
The program acts as a filter.
Returning zero from the program means that the normal perf_event_output handler will not be called and sampling event won't be stored in the ring buffer.

The overflow_handler_context==NULL is an additional safety check to make sure programs are not attached to hw breakpoints and watchdog in case other checks (that prevent that now anyway) get accidentally relaxed in the future.

The program refcnt is incremented in case perf_events are inhereted when target task is forked.
Similar to kprobe and tracepoint programs there is no ioctl to detach the program or swap already attached program. The user space expected to close(perf_event_fd) like it does right now for kprobe+bpf. That restriction simplifies the code quite a bit.

The invocation of overflow_handler in __perf_event_overflow() is now done via READ_ONCE, since that pointer can be replaced when the program is attached while perf_event itself could have been active already. There is no need to do similar treatment for event->prog, since it's assigned only once before it's accessed.

---
 include/linux/bpf.h        |  4 +++
 include/linux/perf_event.h |  2 ++
 kernel/events/core.c       | 85 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 1 deletion(-)
include/linux/bpf.h +4 -0
index 11134238417d..9a904f63f8c1 100644
@@ -297,6 +297,10 @@ static inline struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
 static inline void bpf_prog_put(struct bpf_prog *prog)
 {
 }
+static inline struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
 #endif /* CONFIG_BPF_SYSCALL */
 
 /* verifier prototypes for helper functions called from eBPF programs */
include/linux/perf_event.h +2 -0
index 97bfe62f30d7..dcaaaf3ec8e6 100644
@@ -679,6 +679,8 @@ struct perf_event {
 	u64				(*clock)(void);
 	perf_overflow_handler_t		overflow_handler;
 	void				*overflow_handler_context;
+	perf_overflow_handler_t		orig_overflow_handler;
+	struct bpf_prog			*prog;
 
 #ifdef CONFIG_EVENT_TRACING
 	struct trace_event_call		*tp_event;
kernel/events/core.c +84 -1

120 lines not on this page · raw message

Signature · 1 line
2.8.0
maintainer
#7 lore raw

Re: [PATCH v2 net-next 4/6] perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT programs

include/linux/perf_event.h struct perf_event { · line 684

Quoted 11 lines · Alexei Starovoitov
include/linux/perf_event.h +2 -0
index 97bfe62f30d7..dcaaaf3ec8e6 100644
@@ -679,6 +679,8 @@ struct perf_event {
 	u64				(*clock)(void);
 	perf_overflow_handler_t		overflow_handler;
 	void				*overflow_handler_context;
 
+	perf_overflow_handler_t		orig_overflow_handler;
+	struct bpf_prog			*prog;

Should we put that under CONFIG_BPF_SYSCALL too?

Quoted 17 lines
kernel/events/core.c +8 -0
index 3cfabdf7b942..305433ab2447 100644
@@ -7637,11 +7637,75 @@ static void perf_event_free_filter(struct perf_event *event)
 	ftrace_profile_free_filter(event);
 }
 
+static void bpf_overflow_handler(struct perf_event *event,
+				 struct perf_sample_data *data,
+				 struct pt_regs *regs)
+{
+	struct bpf_perf_event_data_kern ctx = {
+		.data = data,
+		.regs = regs,
+	};

kernel/events/core.c static void perf_event_free_filter(struct perf_event *event) · line 7657

Quoted 10 lines
kernel/events/core.c +10 -0
+	int ret = 0;
+
+#ifdef CONFIG_BPF_SYSCALL
+	preempt_disable();
+	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
+		goto out;
+	rcu_read_lock();
+	ret = BPF_PROG_RUN(event->prog, (void *)&ctx);
+	rcu_read_unlock();
+ out:

Please, no leading space before labels. Use something like:

[diff "default"]

        xfuncname = "^[[:alpha:]$_].*[^:]$"

In your .gitconfig if you want to keep diff output 'sane'.

kernel/events/core.c static void perf_event_free_filter(struct perf_event *event) · line 7665

Quoted 8 lines
kernel/events/core.c +8 -0
+	__this_cpu_dec(bpf_prog_active);
+	preempt_enable();
+#endif
+	if (!ret)
+		return;
+
+	event->orig_overflow_handler(event, data, regs);
+}

Other than that, ACK.

#8 lore raw

Re: [PATCH v2 net-next 4/6] perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT programs

Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Alexei Starovoitov
include/linux/perf_event.h +0 -0
index 97bfe62f30d7..dcaaaf3ec8e6 100644
@@ -679,6 +679,8 @@ struct perf_event {
 	u64				(*clock)(void);
 	perf_overflow_handler_t		overflow_handler;
 	void				*overflow_handler_context;
Quoted 4 lines

include/linux/perf_event.h struct perf_event { · line 683

Quoted 2 lines
include/linux/perf_event.h +2 -0
+	perf_overflow_handler_t		orig_overflow_handler;
+	struct bpf_prog			*prog;

Should we put that under CONFIG_BPF_SYSCALL too?

sure. will do.

Quoted 21 lines
Quoted 21 lines
kernel/events/core.c +12 -0
index 3cfabdf7b942..305433ab2447 100644
@@ -7637,11 +7637,75 @@ static void perf_event_free_filter(struct perf_event *event)
 	ftrace_profile_free_filter(event);
 }
 
+static void bpf_overflow_handler(struct perf_event *event,
+				 struct perf_sample_data *data,
+				 struct pt_regs *regs)
+{
+	struct bpf_perf_event_data_kern ctx = {
+		.data = data,
+		.regs = regs,
+	};
+	int ret = 0;
+
+#ifdef CONFIG_BPF_SYSCALL
+	preempt_disable();
Quoted 8 lines

kernel/events/core.c static void perf_event_free_filter(struct perf_event *event) · line 7657

Quoted 6 lines
kernel/events/core.c +6 -0
+	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
+		goto out;
+	rcu_read_lock();
+	ret = BPF_PROG_RUN(event->prog, (void *)&ctx);
+	rcu_read_unlock();
+ out:

Please, no leading space before labels. Use something like:

good catch.
sadly checkpatch didn't complain.

Quoted 4 lines

[diff "default"]

        xfuncname = "^[[:alpha:]$_].*[^:]$"

In your .gitconfig if you want to keep diff output 'sane'.

interesting trick. don't remember being bitten by it. This extra space was a typo.

Quoted 10 lines

kernel/events/core.c static void perf_event_free_filter(struct perf_event *event) · line 7665

Quoted 8 lines
kernel/events/core.c +8 -0
+	__this_cpu_dec(bpf_prog_active);
+	preempt_enable();
+#endif
+	if (!ret)
+		return;
+
+	event->orig_overflow_handler(event, data, regs);
+}

Other than that, ACK.

Thanks!

maintainer
#9 lore raw

Re: [PATCH v2 net-next 4/6] perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT programs

Quoted 6 lines · Alexei Starovoitov
Quoted 1 line · Peter Zijlstra

Please, no leading space before labels. Use something like:

good catch.
sadly checkpatch didn't complain.

Right, a lot of people do it on purpose to avoid diff seeing the label as the function for --show-c-function. I just find the style annoying and 'fixed' diff.

Now, if the option would've been called --show-function (without the explicit reference to C) one could argue that seeing this form is useful for .S files but... ;-)

Quoted 7 lines
Quoted 4 lines

[diff "default"]

        xfuncname = "^[[:alpha:]$_].*[^:]$"

In your .gitconfig if you want to keep diff output 'sane'.

interesting trick. don't remember being bitten by it. This extra space was a typo.

Example below, see the difference in the @@ line. I find the first (fixed) to be much more useful.

With:

kernel/events/core.c +1 -0
index 8b3ad4e26548..cc2af0188924 100644
@@ -6238,6 +6238,7 @@ static void perf_pmu_output_stop(struct perf_event *event)
 			goto restart;
 		}
 	}
+	/* ponies */
 	rcu_read_unlock();
 }
 

Without:

kernel/events/core.c +1 -0
index 8b3ad4e26548..cc2af0188924 100644
@@ -6238,6 +6238,7 @@ restart:
 			goto restart;
 		}
 	}
+	/* ponies */
 	rcu_read_unlock();
 }
 
#10 lore raw

PATCH v2 5/6 samples/bpf: add perf_event+bpf example

In reply to Alexei Starovoitov

The bpf program is called 50 times a second and does hashmap[kern&user_stackid]++ It's primary purpose to check that key bpf helpers like map lookup, update, get_stackid, trace_printk and ctx access are all working.
It checks:
- PERF_COUNT_HW_CPU_CYCLES on all cpus
- PERF_COUNT_HW_CPU_CYCLES for current process and inherited perf_events to children
- PERF_COUNT_SW_CPU_CLOCK on all cpus
- PERF_COUNT_SW_CPU_CLOCK for current process

---
 samples/bpf/Makefile           |   4 +
 samples/bpf/bpf_helpers.h      |   2 +
 samples/bpf/bpf_load.c         |   7 +-
 samples/bpf/trace_event_kern.c |  65 +++++++++++++
 samples/bpf/trace_event_user.c | 213 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 290 insertions(+), 1 deletion(-)
 create mode 100644 samples/bpf/trace_event_kern.c
 create mode 100644 samples/bpf/trace_event_user.c
samples/bpf/Makefile +4 -0
index db3cb061bfcd..a69cf9045285 100644
@@ -25,6 +25,7 @@ hostprogs-y += test_cgrp2_array_pin
 hostprogs-y += xdp1
 hostprogs-y += xdp2
 hostprogs-y += test_current_task_under_cgroup
+hostprogs-y += trace_event
 
 test_verifier-objs := test_verifier.o libbpf.o
 test_maps-objs := test_maps.o libbpf.o
@@ -52,6 +53,7 @@ xdp1-objs := bpf_load.o libbpf.o xdp1_user.o
 xdp2-objs := bpf_load.o libbpf.o xdp1_user.o
 test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
 				       test_current_task_under_cgroup_user.o
+trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -79,6 +81,7 @@ always += test_cgrp2_tc_kern.o
 always += xdp1_kern.o
 always += xdp2_kern.o
 always += test_current_task_under_cgroup_kern.o
+always += trace_event_kern.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 
@@ -103,6 +106,7 @@ HOSTLOADLIBES_test_overhead += -lelf -lrt
 HOSTLOADLIBES_xdp1 += -lelf
 HOSTLOADLIBES_xdp2 += -lelf
 HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
+HOSTLOADLIBES_trace_event += -lelf
 
 # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
 #  make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
samples/bpf/bpf_helpers.h +2 -0
index bbdf62a1e45e..90f44bd2045e 100644
@@ -55,6 +55,8 @@ static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) =
 	(void *) BPF_FUNC_skb_get_tunnel_opt;
 static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
 	(void *) BPF_FUNC_skb_set_tunnel_opt;
+static unsigned long long (*bpf_get_prandom_u32)(void) =
+	(void *) BPF_FUNC_get_prandom_u32;
 
 /* llvm builtin functions that eBPF C program may use to
  * emit BPF_LD_ABS and BPF_LD_IND instructions
samples/bpf/bpf_load.c +6 -1
index 0cfda2320320..97913e109b14 100644
@@ -51,6 +51,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
 	bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
 	bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0;
 	bool is_xdp = strncmp(event, "xdp", 3) == 0;
+	bool is_perf_event = strncmp(event, "perf_event", 10) == 0;
 	enum bpf_prog_type prog_type;
 	char buf[256];
 	int fd, efd, err, id;
@@ -69,6 +70,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
 		prog_type = BPF_PROG_TYPE_TRACEPOINT;
 	} else if (is_xdp) {
 		prog_type = BPF_PROG_TYPE_XDP;
+	} else if (is_perf_event) {
+		prog_type = BPF_PROG_TYPE_PERF_EVENT;
 	} else {
 		printf("Unknown event '%s'\n", event);
 		return -1;
@@ -82,7 +85,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
 
 	prog_fd[prog_cnt++] = fd;
 
-	if (is_xdp)
+	if (is_xdp || is_perf_event)
 		return 0;
 
 	if (is_socket) {
@@ -326,6 +329,7 @@ int load_bpf_file(char *path)
 			    memcmp(shname_prog, "kretprobe/", 10) == 0 ||
 			    memcmp(shname_prog, "tracepoint/", 11) == 0 ||
 			    memcmp(shname_prog, "xdp", 3) == 0 ||
+			    memcmp(shname_prog, "perf_event", 10) == 0 ||
 			    memcmp(shname_prog, "socket", 6) == 0)
 				load_and_attach(shname_prog, insns, data_prog->d_size);
 		}
@@ -344,6 +348,7 @@ int load_bpf_file(char *path)
 		    memcmp(shname, "kretprobe/", 10) == 0 ||
 		    memcmp(shname, "tracepoint/", 11) == 0 ||
 		    memcmp(shname, "xdp", 3) == 0 ||
+		    memcmp(shname, "perf_event", 10) == 0 ||
 		    memcmp(shname, "socket", 6) == 0)
 			load_and_attach(shname, data->d_buf, data->d_size);
 	}
samples/bpf/trace_event_kern.c new file +65 -0

65 lines not on this page · raw message

samples/bpf/trace_event_user.c new file +213 -0

213 lines not on this page · raw message

Signature · 1 line
2.8.0
#11 lore raw

PATCH v2 6/6 samples/bpf: add sampleip example

In reply to Alexei Starovoitov

From: Brendan Gregg <[email protected]>

sample instruction pointer and frequency count in a BPF map

---
 samples/bpf/Makefile        |   4 +
 samples/bpf/sampleip_kern.c |  38 +++++++++
 samples/bpf/sampleip_user.c | 196 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 samples/bpf/sampleip_kern.c
 create mode 100644 samples/bpf/sampleip_user.c
samples/bpf/Makefile +4 -0
index a69cf9045285..12b7304d55dc 100644
@@ -26,6 +26,7 @@ hostprogs-y += xdp1
 hostprogs-y += xdp2
 hostprogs-y += test_current_task_under_cgroup
 hostprogs-y += trace_event
+hostprogs-y += sampleip
 
 test_verifier-objs := test_verifier.o libbpf.o
 test_maps-objs := test_maps.o libbpf.o
@@ -54,6 +55,7 @@ xdp2-objs := bpf_load.o libbpf.o xdp1_user.o
 test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
 				       test_current_task_under_cgroup_user.o
 trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
+sampleip-objs := bpf_load.o libbpf.o sampleip_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -82,6 +84,7 @@ always += xdp1_kern.o
 always += xdp2_kern.o
 always += test_current_task_under_cgroup_kern.o
 always += trace_event_kern.o
+always += sampleip_kern.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 
@@ -107,6 +110,7 @@ HOSTLOADLIBES_xdp1 += -lelf
 HOSTLOADLIBES_xdp2 += -lelf
 HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
 HOSTLOADLIBES_trace_event += -lelf
+HOSTLOADLIBES_sampleip += -lelf
 
 # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
 #  make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
samples/bpf/sampleip_kern.c new file +38 -0
new file mode 100644
index 000000000000..774a681f374a
@@ -0,0 +1,38 @@
+/* Copyright 2016 Netflix, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#include <linux/version.h>
+#include <linux/ptrace.h>
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/bpf_perf_event.h>
+#include "bpf_helpers.h"
+
+#define MAX_IPS		8192
+
+struct bpf_map_def SEC("maps") ip_map = {
+	.type = BPF_MAP_TYPE_HASH,
+	.key_size = sizeof(u64),
+	.value_size = sizeof(u32),
+	.max_entries = MAX_IPS,
+};
+
+SEC("perf_event")
+int do_sample(struct bpf_perf_event_data *ctx)
+{
+	u64 ip;
+	u32 *value, init_val = 1;
+
+	ip = ctx->regs.ip;
+	value = bpf_map_lookup_elem(&ip_map, &ip);
+	if (value)
+		*value += 1;
+	else
+		/* E2BIG not tested for this example only */
+		bpf_map_update_elem(&ip_map, &ip, &init_val, BPF_NOEXIST);
+
+	return 0;
+}
+char _license[] SEC("license") = "GPL";
samples/bpf/sampleip_user.c new file +196 -0

196 lines not on this page · raw message

Signature · 1 line
2.8.0
Tested-by on the v2 series
#12 lore raw
In reply to Alexei Starovoitov
Quoted 6 lines · Alexei Starovoitov

Hi Peter, Dave,

this patch set is a follow up to the discussion:
https://lkml.kernel.org/r/20160804142853.GO6862%20()%20twins%20!%20programming%20!%20kicks-ass%20!%20net
It turned out to be simpler than what we discussed.

Quoted 7 lines

Patches 1-3 is bpf-side prep for the main patch 4
that adds bpf program as an overflow_handler to sw and hw perf_events. Peter, please review.

Patches 5 and 6 are examples from myself and Brendan.

v1-v2: fixed issues spotted by Peter and Daniel.

Thanks Alexei!

Brendan