summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/xdp_sample_pkts_kern.c66
-rw-r--r--samples/bpf/xdp_sample_pkts_user.c169
3 files changed, 239 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 1303af10e54d..9ea2f7b64869 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -52,6 +52,7 @@ hostprogs-y += xdp_adjust_tail
52hostprogs-y += xdpsock 52hostprogs-y += xdpsock
53hostprogs-y += xdp_fwd 53hostprogs-y += xdp_fwd
54hostprogs-y += task_fd_query 54hostprogs-y += task_fd_query
55hostprogs-y += xdp_sample_pkts
55 56
56# Libbpf dependencies 57# Libbpf dependencies
57LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a 58LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a
@@ -107,6 +108,7 @@ xdp_adjust_tail-objs := xdp_adjust_tail_user.o
107xdpsock-objs := bpf_load.o xdpsock_user.o 108xdpsock-objs := bpf_load.o xdpsock_user.o
108xdp_fwd-objs := bpf_load.o xdp_fwd_user.o 109xdp_fwd-objs := bpf_load.o xdp_fwd_user.o
109task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS) 110task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS)
111xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
110 112
111# Tell kbuild to always build the programs 113# Tell kbuild to always build the programs
112always := $(hostprogs-y) 114always := $(hostprogs-y)
@@ -163,6 +165,7 @@ always += xdp_adjust_tail_kern.o
163always += xdpsock_kern.o 165always += xdpsock_kern.o
164always += xdp_fwd_kern.o 166always += xdp_fwd_kern.o
165always += task_fd_query_kern.o 167always += task_fd_query_kern.o
168always += xdp_sample_pkts_kern.o
166 169
167HOSTCFLAGS += -I$(objtree)/usr/include 170HOSTCFLAGS += -I$(objtree)/usr/include
168HOSTCFLAGS += -I$(srctree)/tools/lib/ 171HOSTCFLAGS += -I$(srctree)/tools/lib/
@@ -179,6 +182,7 @@ HOSTCFLAGS_spintest_user.o += -I$(srctree)/tools/lib/bpf/
179HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/ 182HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/
180HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/ 183HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/
181HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/ 184HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/
185HOSTCFLAGS_xdp_sample_pkts_user.o += -I$(srctree)/tools/lib/bpf/
182 186
183HOST_LOADLIBES += $(LIBBPF) -lelf 187HOST_LOADLIBES += $(LIBBPF) -lelf
184HOSTLOADLIBES_tracex4 += -lrt 188HOSTLOADLIBES_tracex4 += -lrt
diff --git a/samples/bpf/xdp_sample_pkts_kern.c b/samples/bpf/xdp_sample_pkts_kern.c
new file mode 100644
index 000000000000..f7ca8b850978
--- /dev/null
+++ b/samples/bpf/xdp_sample_pkts_kern.c
@@ -0,0 +1,66 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/ptrace.h>
3#include <linux/version.h>
4#include <uapi/linux/bpf.h>
5#include "bpf_helpers.h"
6
7#define SAMPLE_SIZE 64ul
8#define MAX_CPUS 128
9
10#define bpf_printk(fmt, ...) \
11({ \
12 char ____fmt[] = fmt; \
13 bpf_trace_printk(____fmt, sizeof(____fmt), \
14 ##__VA_ARGS__); \
15})
16
17struct bpf_map_def SEC("maps") my_map = {
18 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
19 .key_size = sizeof(int),
20 .value_size = sizeof(u32),
21 .max_entries = MAX_CPUS,
22};
23
24SEC("xdp_sample")
25int xdp_sample_prog(struct xdp_md *ctx)
26{
27 void *data_end = (void *)(long)ctx->data_end;
28 void *data = (void *)(long)ctx->data;
29
30 /* Metadata will be in the perf event before the packet data. */
31 struct S {
32 u16 cookie;
33 u16 pkt_len;
34 } __packed metadata;
35
36 if (data < data_end) {
37 /* The XDP perf_event_output handler will use the upper 32 bits
38 * of the flags argument as a number of bytes to include of the
39 * packet payload in the event data. If the size is too big, the
40 * call to bpf_perf_event_output will fail and return -EFAULT.
41 *
42 * See bpf_xdp_event_output in net/core/filter.c.
43 *
44 * The BPF_F_CURRENT_CPU flag means that the event output fd
45 * will be indexed by the CPU number in the event map.
46 */
47 u64 flags = BPF_F_CURRENT_CPU;
48 u16 sample_size;
49 int ret;
50
51 metadata.cookie = 0xdead;
52 metadata.pkt_len = (u16)(data_end - data);
53 sample_size = min(metadata.pkt_len, SAMPLE_SIZE);
54 flags |= (u64)sample_size << 32;
55
56 ret = bpf_perf_event_output(ctx, &my_map, flags,
57 &metadata, sizeof(metadata));
58 if (ret)
59 bpf_printk("perf_event_output failed: %d\n", ret);
60 }
61
62 return XDP_PASS;
63}
64
65char _license[] SEC("license") = "GPL";
66u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/xdp_sample_pkts_user.c b/samples/bpf/xdp_sample_pkts_user.c
new file mode 100644
index 000000000000..8dd87c1eb560
--- /dev/null
+++ b/samples/bpf/xdp_sample_pkts_user.c
@@ -0,0 +1,169 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <linux/perf_event.h>
6#include <linux/bpf.h>
7#include <net/if.h>
8#include <errno.h>
9#include <assert.h>
10#include <sys/sysinfo.h>
11#include <sys/ioctl.h>
12#include <signal.h>
13#include <libbpf.h>
14#include <bpf/bpf.h>
15
16#include "perf-sys.h"
17#include "trace_helpers.h"
18
19#define MAX_CPUS 128
20static int pmu_fds[MAX_CPUS], if_idx;
21static struct perf_event_mmap_page *headers[MAX_CPUS];
22static char *if_name;
23
24static int do_attach(int idx, int fd, const char *name)
25{
26 int err;
27
28 err = bpf_set_link_xdp_fd(idx, fd, 0);
29 if (err < 0)
30 printf("ERROR: failed to attach program to %s\n", name);
31
32 return err;
33}
34
35static int do_detach(int idx, const char *name)
36{
37 int err;
38
39 err = bpf_set_link_xdp_fd(idx, -1, 0);
40 if (err < 0)
41 printf("ERROR: failed to detach program from %s\n", name);
42
43 return err;
44}
45
46#define SAMPLE_SIZE 64
47
48static int print_bpf_output(void *data, int size)
49{
50 struct {
51 __u16 cookie;
52 __u16 pkt_len;
53 __u8 pkt_data[SAMPLE_SIZE];
54 } __packed *e = data;
55 int i;
56
57 if (e->cookie != 0xdead) {
58 printf("BUG cookie %x sized %d\n",
59 e->cookie, size);
60 return LIBBPF_PERF_EVENT_ERROR;
61 }
62
63 printf("Pkt len: %-5d bytes. Ethernet hdr: ", e->pkt_len);
64 for (i = 0; i < 14 && i < e->pkt_len; i++)
65 printf("%02x ", e->pkt_data[i]);
66 printf("\n");
67
68 return LIBBPF_PERF_EVENT_CONT;
69}
70
71static void test_bpf_perf_event(int map_fd, int num)
72{
73 struct perf_event_attr attr = {
74 .sample_type = PERF_SAMPLE_RAW,
75 .type = PERF_TYPE_SOFTWARE,
76 .config = PERF_COUNT_SW_BPF_OUTPUT,
77 .wakeup_events = 1, /* get an fd notification for every event */
78 };
79 int i;
80
81 for (i = 0; i < num; i++) {
82 int key = i;
83
84 pmu_fds[i] = sys_perf_event_open(&attr, -1/*pid*/, i/*cpu*/,
85 -1/*group_fd*/, 0);
86
87 assert(pmu_fds[i] >= 0);
88 assert(bpf_map_update_elem(map_fd, &key,
89 &pmu_fds[i], BPF_ANY) == 0);
90 ioctl(pmu_fds[i], PERF_EVENT_IOC_ENABLE, 0);
91 }
92}
93
94static void sig_handler(int signo)
95{
96 do_detach(if_idx, if_name);
97 exit(0);
98}
99
100int main(int argc, char **argv)
101{
102 struct bpf_prog_load_attr prog_load_attr = {
103 .prog_type = BPF_PROG_TYPE_XDP,
104 };
105 struct bpf_object *obj;
106 struct bpf_map *map;
107 int prog_fd, map_fd;
108 char filename[256];
109 int ret, err, i;
110 int numcpus;
111
112 if (argc < 2) {
113 printf("Usage: %s <ifname>\n", argv[0]);
114 return 1;
115 }
116
117 numcpus = get_nprocs();
118 if (numcpus > MAX_CPUS)
119 numcpus = MAX_CPUS;
120
121 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
122 prog_load_attr.file = filename;
123
124 if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
125 return 1;
126
127 if (!prog_fd) {
128 printf("load_bpf_file: %s\n", strerror(errno));
129 return 1;
130 }
131
132 map = bpf_map__next(NULL, obj);
133 if (!map) {
134 printf("finding a map in obj file failed\n");
135 return 1;
136 }
137 map_fd = bpf_map__fd(map);
138
139 if_idx = if_nametoindex(argv[1]);
140 if (!if_idx)
141 if_idx = strtoul(argv[1], NULL, 0);
142
143 if (!if_idx) {
144 fprintf(stderr, "Invalid ifname\n");
145 return 1;
146 }
147 if_name = argv[1];
148 err = do_attach(if_idx, prog_fd, argv[1]);
149 if (err)
150 return err;
151
152 if (signal(SIGINT, sig_handler) ||
153 signal(SIGHUP, sig_handler) ||
154 signal(SIGTERM, sig_handler)) {
155 perror("signal");
156 return 1;
157 }
158
159 test_bpf_perf_event(map_fd, numcpus);
160
161 for (i = 0; i < numcpus; i++)
162 if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0)
163 return 1;
164
165 ret = perf_event_poller_multi(pmu_fds, headers, numcpus,
166 print_bpf_output);
167 kill(0, SIGINT);
168 return ret;
169}