aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2015-03-25 15:49:23 -0400
committerIngo Molnar <mingo@kernel.org>2015-04-02 07:25:50 -0400
commitb896c4f95ab4052d6bad3acde95167d30242a84f (patch)
tree8c18a3ca9f2b389823d7181db606fa3c8d2eccc7 /samples/bpf
parent9c959c863f8217a2ff3d7c296e8223654d240569 (diff)
samples/bpf: Add simple non-portable kprobe filter example
tracex1_kern.c - C program compiled into BPF. It attaches to kprobe:netif_receive_skb() When skb->dev->name == "lo", it prints sample debug message into trace_pipe via bpf_trace_printk() helper function. tracex1_user.c - corresponding user space component that: - loads BPF program via bpf() syscall - opens kprobes:netif_receive_skb event via perf_event_open() syscall - attaches the program to event via ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); - prints from trace_pipe Note, this BPF program is non-portable. It must be recompiled with current kernel headers. kprobe is not a stable ABI and BPF+kprobe scripts may no longer be meaningful when kernel internals change. No matter in what way the kernel changes, neither the kprobe, nor the BPF program can ever crash or corrupt the kernel, assuming the kprobes, perf and BPF subsystem has no bugs. The verifier will detect that the program is using bpf_trace_printk() and the kernel will print 'this is a DEBUG kernel' warning banner, which means that bpf_trace_printk() should be used for debugging of the BPF program only. Usage: $ sudo tracex1 ping-19826 [000] d.s2 63103.382648: : skb ffff880466b1ca00 len 84 ping-19826 [000] d.s2 63103.382684: : skb ffff880466b1d300 len 84 ping-19826 [000] d.s2 63104.382533: : skb ffff880466b1ca00 len 84 ping-19826 [000] d.s2 63104.382594: : skb ffff880466b1d300 len 84 Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: David S. Miller <davem@davemloft.net> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/1427312966-8434-7-git-send-email-ast@plumgrid.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'samples/bpf')
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/bpf_helpers.h6
-rw-r--r--samples/bpf/bpf_load.c125
-rw-r--r--samples/bpf/bpf_load.h3
-rw-r--r--samples/bpf/libbpf.c14
-rw-r--r--samples/bpf/libbpf.h5
-rw-r--r--samples/bpf/sock_example.c2
-rw-r--r--samples/bpf/test_verifier.c2
-rw-r--r--samples/bpf/tracex1_kern.c50
-rw-r--r--samples/bpf/tracex1_user.c25
10 files changed, 224 insertions, 12 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index b5b3600dcdf5..51f6f01e5a3a 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -6,23 +6,27 @@ hostprogs-y := test_verifier test_maps
6hostprogs-y += sock_example 6hostprogs-y += sock_example
7hostprogs-y += sockex1 7hostprogs-y += sockex1
8hostprogs-y += sockex2 8hostprogs-y += sockex2
9hostprogs-y += tracex1
9 10
10test_verifier-objs := test_verifier.o libbpf.o 11test_verifier-objs := test_verifier.o libbpf.o
11test_maps-objs := test_maps.o libbpf.o 12test_maps-objs := test_maps.o libbpf.o
12sock_example-objs := sock_example.o libbpf.o 13sock_example-objs := sock_example.o libbpf.o
13sockex1-objs := bpf_load.o libbpf.o sockex1_user.o 14sockex1-objs := bpf_load.o libbpf.o sockex1_user.o
14sockex2-objs := bpf_load.o libbpf.o sockex2_user.o 15sockex2-objs := bpf_load.o libbpf.o sockex2_user.o
16tracex1-objs := bpf_load.o libbpf.o tracex1_user.o
15 17
16# Tell kbuild to always build the programs 18# Tell kbuild to always build the programs
17always := $(hostprogs-y) 19always := $(hostprogs-y)
18always += sockex1_kern.o 20always += sockex1_kern.o
19always += sockex2_kern.o 21always += sockex2_kern.o
22always += tracex1_kern.o
20 23
21HOSTCFLAGS += -I$(objtree)/usr/include 24HOSTCFLAGS += -I$(objtree)/usr/include
22 25
23HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable 26HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable
24HOSTLOADLIBES_sockex1 += -lelf 27HOSTLOADLIBES_sockex1 += -lelf
25HOSTLOADLIBES_sockex2 += -lelf 28HOSTLOADLIBES_sockex2 += -lelf
29HOSTLOADLIBES_tracex1 += -lelf
26 30
27# point this to your LLVM backend with bpf support 31# point this to your LLVM backend with bpf support
28LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc 32LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index ca0333146006..1c872bcf5a80 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -15,6 +15,12 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value,
15 (void *) BPF_FUNC_map_update_elem; 15 (void *) BPF_FUNC_map_update_elem;
16static int (*bpf_map_delete_elem)(void *map, void *key) = 16static int (*bpf_map_delete_elem)(void *map, void *key) =
17 (void *) BPF_FUNC_map_delete_elem; 17 (void *) BPF_FUNC_map_delete_elem;
18static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
19 (void *) BPF_FUNC_probe_read;
20static unsigned long long (*bpf_ktime_get_ns)(void) =
21 (void *) BPF_FUNC_ktime_get_ns;
22static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
23 (void *) BPF_FUNC_trace_printk;
18 24
19/* llvm builtin functions that eBPF C program may use to 25/* llvm builtin functions that eBPF C program may use to
20 * emit BPF_LD_ABS and BPF_LD_IND instructions 26 * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 1831d236382b..38dac5a53b51 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -8,29 +8,70 @@
8#include <unistd.h> 8#include <unistd.h>
9#include <string.h> 9#include <string.h>
10#include <stdbool.h> 10#include <stdbool.h>
11#include <stdlib.h>
11#include <linux/bpf.h> 12#include <linux/bpf.h>
12#include <linux/filter.h> 13#include <linux/filter.h>
14#include <linux/perf_event.h>
15#include <sys/syscall.h>
16#include <sys/ioctl.h>
17#include <sys/mman.h>
18#include <poll.h>
13#include "libbpf.h" 19#include "libbpf.h"
14#include "bpf_helpers.h" 20#include "bpf_helpers.h"
15#include "bpf_load.h" 21#include "bpf_load.h"
16 22
23#define DEBUGFS "/sys/kernel/debug/tracing/"
24
17static char license[128]; 25static char license[128];
26static int kern_version;
18static bool processed_sec[128]; 27static bool processed_sec[128];
19int map_fd[MAX_MAPS]; 28int map_fd[MAX_MAPS];
20int prog_fd[MAX_PROGS]; 29int prog_fd[MAX_PROGS];
30int event_fd[MAX_PROGS];
21int prog_cnt; 31int prog_cnt;
22 32
23static int load_and_attach(const char *event, struct bpf_insn *prog, int size) 33static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
24{ 34{
25 int fd;
26 bool is_socket = strncmp(event, "socket", 6) == 0; 35 bool is_socket = strncmp(event, "socket", 6) == 0;
27 36 bool is_kprobe = strncmp(event, "kprobe/", 7) == 0;
28 if (!is_socket) 37 bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
29 /* tracing events tbd */ 38 enum bpf_prog_type prog_type;
39 char buf[256];
40 int fd, efd, err, id;
41 struct perf_event_attr attr = {};
42
43 attr.type = PERF_TYPE_TRACEPOINT;
44 attr.sample_type = PERF_SAMPLE_RAW;
45 attr.sample_period = 1;
46 attr.wakeup_events = 1;
47
48 if (is_socket) {
49 prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
50 } else if (is_kprobe || is_kretprobe) {
51 prog_type = BPF_PROG_TYPE_KPROBE;
52 } else {
53 printf("Unknown event '%s'\n", event);
30 return -1; 54 return -1;
55 }
56
57 if (is_kprobe || is_kretprobe) {
58 if (is_kprobe)
59 event += 7;
60 else
61 event += 10;
62
63 snprintf(buf, sizeof(buf),
64 "echo '%c:%s %s' >> /sys/kernel/debug/tracing/kprobe_events",
65 is_kprobe ? 'p' : 'r', event, event);
66 err = system(buf);
67 if (err < 0) {
68 printf("failed to create kprobe '%s' error '%s'\n",
69 event, strerror(errno));
70 return -1;
71 }
72 }
31 73
32 fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, 74 fd = bpf_prog_load(prog_type, prog, size, license, kern_version);
33 prog, size, license);
34 75
35 if (fd < 0) { 76 if (fd < 0) {
36 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf); 77 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf);
@@ -39,6 +80,41 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
39 80
40 prog_fd[prog_cnt++] = fd; 81 prog_fd[prog_cnt++] = fd;
41 82
83 if (is_socket)
84 return 0;
85
86 strcpy(buf, DEBUGFS);
87 strcat(buf, "events/kprobes/");
88 strcat(buf, event);
89 strcat(buf, "/id");
90
91 efd = open(buf, O_RDONLY, 0);
92 if (efd < 0) {
93 printf("failed to open event %s\n", event);
94 return -1;
95 }
96
97 err = read(efd, buf, sizeof(buf));
98 if (err < 0 || err >= sizeof(buf)) {
99 printf("read from '%s' failed '%s'\n", event, strerror(errno));
100 return -1;
101 }
102
103 close(efd);
104
105 buf[err] = 0;
106 id = atoi(buf);
107 attr.config = id;
108
109 efd = perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0);
110 if (efd < 0) {
111 printf("event %d fd %d err %s\n", id, efd, strerror(errno));
112 return -1;
113 }
114 event_fd[prog_cnt - 1] = efd;
115 ioctl(efd, PERF_EVENT_IOC_ENABLE, 0);
116 ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd);
117
42 return 0; 118 return 0;
43} 119}
44 120
@@ -135,6 +211,9 @@ int load_bpf_file(char *path)
135 if (gelf_getehdr(elf, &ehdr) != &ehdr) 211 if (gelf_getehdr(elf, &ehdr) != &ehdr)
136 return 1; 212 return 1;
137 213
214 /* clear all kprobes */
215 i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
216
138 /* scan over all elf sections to get license and map info */ 217 /* scan over all elf sections to get license and map info */
139 for (i = 1; i < ehdr.e_shnum; i++) { 218 for (i = 1; i < ehdr.e_shnum; i++) {
140 219
@@ -149,6 +228,14 @@ int load_bpf_file(char *path)
149 if (strcmp(shname, "license") == 0) { 228 if (strcmp(shname, "license") == 0) {
150 processed_sec[i] = true; 229 processed_sec[i] = true;
151 memcpy(license, data->d_buf, data->d_size); 230 memcpy(license, data->d_buf, data->d_size);
231 } else if (strcmp(shname, "version") == 0) {
232 processed_sec[i] = true;
233 if (data->d_size != sizeof(int)) {
234 printf("invalid size of version section %zd\n",
235 data->d_size);
236 return 1;
237 }
238 memcpy(&kern_version, data->d_buf, sizeof(int));
152 } else if (strcmp(shname, "maps") == 0) { 239 } else if (strcmp(shname, "maps") == 0) {
153 processed_sec[i] = true; 240 processed_sec[i] = true;
154 if (load_maps(data->d_buf, data->d_size)) 241 if (load_maps(data->d_buf, data->d_size))
@@ -178,7 +265,8 @@ int load_bpf_file(char *path)
178 if (parse_relo_and_apply(data, symbols, &shdr, insns)) 265 if (parse_relo_and_apply(data, symbols, &shdr, insns))
179 continue; 266 continue;
180 267
181 if (memcmp(shname_prog, "events/", 7) == 0 || 268 if (memcmp(shname_prog, "kprobe/", 7) == 0 ||
269 memcmp(shname_prog, "kretprobe/", 10) == 0 ||
182 memcmp(shname_prog, "socket", 6) == 0) 270 memcmp(shname_prog, "socket", 6) == 0)
183 load_and_attach(shname_prog, insns, data_prog->d_size); 271 load_and_attach(shname_prog, insns, data_prog->d_size);
184 } 272 }
@@ -193,7 +281,8 @@ int load_bpf_file(char *path)
193 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 281 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data))
194 continue; 282 continue;
195 283
196 if (memcmp(shname, "events/", 7) == 0 || 284 if (memcmp(shname, "kprobe/", 7) == 0 ||
285 memcmp(shname, "kretprobe/", 10) == 0 ||
197 memcmp(shname, "socket", 6) == 0) 286 memcmp(shname, "socket", 6) == 0)
198 load_and_attach(shname, data->d_buf, data->d_size); 287 load_and_attach(shname, data->d_buf, data->d_size);
199 } 288 }
@@ -201,3 +290,23 @@ int load_bpf_file(char *path)
201 close(fd); 290 close(fd);
202 return 0; 291 return 0;
203} 292}
293
294void read_trace_pipe(void)
295{
296 int trace_fd;
297
298 trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
299 if (trace_fd < 0)
300 return;
301
302 while (1) {
303 static char buf[4096];
304 ssize_t sz;
305
306 sz = read(trace_fd, buf, sizeof(buf));
307 if (sz > 0) {
308 buf[sz] = 0;
309 puts(buf);
310 }
311 }
312}
diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h
index 27789a34f5e6..cbd7c2b532b9 100644
--- a/samples/bpf/bpf_load.h
+++ b/samples/bpf/bpf_load.h
@@ -6,6 +6,7 @@
6 6
7extern int map_fd[MAX_MAPS]; 7extern int map_fd[MAX_MAPS];
8extern int prog_fd[MAX_PROGS]; 8extern int prog_fd[MAX_PROGS];
9extern int event_fd[MAX_PROGS];
9 10
10/* parses elf file compiled by llvm .c->.o 11/* parses elf file compiled by llvm .c->.o
11 * . parses 'maps' section and creates maps via BPF syscall 12 * . parses 'maps' section and creates maps via BPF syscall
@@ -21,4 +22,6 @@ extern int prog_fd[MAX_PROGS];
21 */ 22 */
22int load_bpf_file(char *path); 23int load_bpf_file(char *path);
23 24
25void read_trace_pipe(void);
26
24#endif 27#endif
diff --git a/samples/bpf/libbpf.c b/samples/bpf/libbpf.c
index 46d50b7ddf79..7e1efa7e2ed7 100644
--- a/samples/bpf/libbpf.c
+++ b/samples/bpf/libbpf.c
@@ -81,7 +81,7 @@ char bpf_log_buf[LOG_BUF_SIZE];
81 81
82int bpf_prog_load(enum bpf_prog_type prog_type, 82int bpf_prog_load(enum bpf_prog_type prog_type,
83 const struct bpf_insn *insns, int prog_len, 83 const struct bpf_insn *insns, int prog_len,
84 const char *license) 84 const char *license, int kern_version)
85{ 85{
86 union bpf_attr attr = { 86 union bpf_attr attr = {
87 .prog_type = prog_type, 87 .prog_type = prog_type,
@@ -93,6 +93,11 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
93 .log_level = 1, 93 .log_level = 1,
94 }; 94 };
95 95
96 /* assign one field outside of struct init to make sure any
97 * padding is zero initialized
98 */
99 attr.kern_version = kern_version;
100
96 bpf_log_buf[0] = 0; 101 bpf_log_buf[0] = 0;
97 102
98 return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); 103 return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
@@ -121,3 +126,10 @@ int open_raw_sock(const char *name)
121 126
122 return sock; 127 return sock;
123} 128}
129
130int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
131 int group_fd, unsigned long flags)
132{
133 return syscall(__NR_perf_event_open, attr, pid, cpu,
134 group_fd, flags);
135}
diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h
index 58c5fe1bdba1..ac7b09672b46 100644
--- a/samples/bpf/libbpf.h
+++ b/samples/bpf/libbpf.h
@@ -13,7 +13,7 @@ int bpf_get_next_key(int fd, void *key, void *next_key);
13 13
14int bpf_prog_load(enum bpf_prog_type prog_type, 14int bpf_prog_load(enum bpf_prog_type prog_type,
15 const struct bpf_insn *insns, int insn_len, 15 const struct bpf_insn *insns, int insn_len,
16 const char *license); 16 const char *license, int kern_version);
17 17
18#define LOG_BUF_SIZE 65536 18#define LOG_BUF_SIZE 65536
19extern char bpf_log_buf[LOG_BUF_SIZE]; 19extern char bpf_log_buf[LOG_BUF_SIZE];
@@ -182,4 +182,7 @@ extern char bpf_log_buf[LOG_BUF_SIZE];
182/* create RAW socket and bind to interface 'name' */ 182/* create RAW socket and bind to interface 'name' */
183int open_raw_sock(const char *name); 183int open_raw_sock(const char *name);
184 184
185struct perf_event_attr;
186int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
187 int group_fd, unsigned long flags);
185#endif 188#endif
diff --git a/samples/bpf/sock_example.c b/samples/bpf/sock_example.c
index c8ad0404416f..a0ce251c5390 100644
--- a/samples/bpf/sock_example.c
+++ b/samples/bpf/sock_example.c
@@ -56,7 +56,7 @@ static int test_sock(void)
56 }; 56 };
57 57
58 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog), 58 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog),
59 "GPL"); 59 "GPL", 0);
60 if (prog_fd < 0) { 60 if (prog_fd < 0) {
61 printf("failed to load prog '%s'\n", strerror(errno)); 61 printf("failed to load prog '%s'\n", strerror(errno));
62 goto cleanup; 62 goto cleanup;
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
index b96175e90363..740ce97cda5e 100644
--- a/samples/bpf/test_verifier.c
+++ b/samples/bpf/test_verifier.c
@@ -689,7 +689,7 @@ static int test(void)
689 689
690 prog_fd = bpf_prog_load(BPF_PROG_TYPE_UNSPEC, prog, 690 prog_fd = bpf_prog_load(BPF_PROG_TYPE_UNSPEC, prog,
691 prog_len * sizeof(struct bpf_insn), 691 prog_len * sizeof(struct bpf_insn),
692 "GPL"); 692 "GPL", 0);
693 693
694 if (tests[i].result == ACCEPT) { 694 if (tests[i].result == ACCEPT) {
695 if (prog_fd < 0) { 695 if (prog_fd < 0) {
diff --git a/samples/bpf/tracex1_kern.c b/samples/bpf/tracex1_kern.c
new file mode 100644
index 000000000000..31620463701a
--- /dev/null
+++ b/samples/bpf/tracex1_kern.c
@@ -0,0 +1,50 @@
1/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/skbuff.h>
8#include <linux/netdevice.h>
9#include <uapi/linux/bpf.h>
10#include <linux/version.h>
11#include "bpf_helpers.h"
12
13#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
14
15/* kprobe is NOT a stable ABI
16 * kernel functions can be removed, renamed or completely change semantics.
17 * Number of arguments and their positions can change, etc.
18 * In such case this bpf+kprobe example will no longer be meaningful
19 */
20SEC("kprobe/__netif_receive_skb_core")
21int bpf_prog1(struct pt_regs *ctx)
22{
23 /* attaches to kprobe netif_receive_skb,
24 * looks for packets on loobpack device and prints them
25 */
26 char devname[IFNAMSIZ] = {};
27 struct net_device *dev;
28 struct sk_buff *skb;
29 int len;
30
31 /* non-portable! works for the given kernel only */
32 skb = (struct sk_buff *) ctx->di;
33
34 dev = _(skb->dev);
35
36 len = _(skb->len);
37
38 bpf_probe_read(devname, sizeof(devname), dev->name);
39
40 if (devname[0] == 'l' && devname[1] == 'o') {
41 char fmt[] = "skb %p len %d\n";
42 /* using bpf_trace_printk() for DEBUG ONLY */
43 bpf_trace_printk(fmt, sizeof(fmt), skb, len);
44 }
45
46 return 0;
47}
48
49char _license[] SEC("license") = "GPL";
50u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/tracex1_user.c b/samples/bpf/tracex1_user.c
new file mode 100644
index 000000000000..31a48183beea
--- /dev/null
+++ b/samples/bpf/tracex1_user.c
@@ -0,0 +1,25 @@
1#include <stdio.h>
2#include <linux/bpf.h>
3#include <unistd.h>
4#include "libbpf.h"
5#include "bpf_load.h"
6
7int main(int ac, char **argv)
8{
9 FILE *f;
10 char filename[256];
11
12 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
13
14 if (load_bpf_file(filename)) {
15 printf("%s", bpf_log_buf);
16 return 1;
17 }
18
19 f = popen("taskset 1 ping -c5 localhost", "r");
20 (void) f;
21
22 read_trace_pipe();
23
24 return 0;
25}