.. | .. |
---|
10 | 10 | #include <sys/sysinfo.h> |
---|
11 | 11 | #include <sys/ioctl.h> |
---|
12 | 12 | #include <signal.h> |
---|
13 | | -#include <libbpf.h> |
---|
| 13 | +#include <bpf/libbpf.h> |
---|
14 | 14 | #include <bpf/bpf.h> |
---|
| 15 | +#include <sys/resource.h> |
---|
| 16 | +#include <libgen.h> |
---|
| 17 | +#include <linux/if_link.h> |
---|
15 | 18 | |
---|
16 | 19 | #include "perf-sys.h" |
---|
17 | | -#include "trace_helpers.h" |
---|
18 | 20 | |
---|
19 | | -#define MAX_CPUS 128 |
---|
20 | | -static int pmu_fds[MAX_CPUS], if_idx; |
---|
21 | | -static struct perf_event_mmap_page *headers[MAX_CPUS]; |
---|
| 21 | +static int if_idx; |
---|
22 | 22 | static char *if_name; |
---|
| 23 | +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; |
---|
| 24 | +static __u32 prog_id; |
---|
| 25 | +static struct perf_buffer *pb = NULL; |
---|
23 | 26 | |
---|
24 | 27 | static int do_attach(int idx, int fd, const char *name) |
---|
25 | 28 | { |
---|
| 29 | + struct bpf_prog_info info = {}; |
---|
| 30 | + __u32 info_len = sizeof(info); |
---|
26 | 31 | int err; |
---|
27 | 32 | |
---|
28 | | - err = bpf_set_link_xdp_fd(idx, fd, 0); |
---|
29 | | - if (err < 0) |
---|
| 33 | + err = bpf_set_link_xdp_fd(idx, fd, xdp_flags); |
---|
| 34 | + if (err < 0) { |
---|
30 | 35 | printf("ERROR: failed to attach program to %s\n", name); |
---|
| 36 | + return err; |
---|
| 37 | + } |
---|
| 38 | + |
---|
| 39 | + err = bpf_obj_get_info_by_fd(fd, &info, &info_len); |
---|
| 40 | + if (err) { |
---|
| 41 | + printf("can't get prog info - %s\n", strerror(errno)); |
---|
| 42 | + return err; |
---|
| 43 | + } |
---|
| 44 | + prog_id = info.id; |
---|
31 | 45 | |
---|
32 | 46 | return err; |
---|
33 | 47 | } |
---|
34 | 48 | |
---|
35 | 49 | static int do_detach(int idx, const char *name) |
---|
36 | 50 | { |
---|
37 | | - int err; |
---|
| 51 | + __u32 curr_prog_id = 0; |
---|
| 52 | + int err = 0; |
---|
38 | 53 | |
---|
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); |
---|
| 54 | + err = bpf_get_link_xdp_id(idx, &curr_prog_id, xdp_flags); |
---|
| 55 | + if (err) { |
---|
| 56 | + printf("bpf_get_link_xdp_id failed\n"); |
---|
| 57 | + return err; |
---|
| 58 | + } |
---|
| 59 | + if (prog_id == curr_prog_id) { |
---|
| 60 | + err = bpf_set_link_xdp_fd(idx, -1, xdp_flags); |
---|
| 61 | + if (err < 0) |
---|
| 62 | + printf("ERROR: failed to detach prog from %s\n", name); |
---|
| 63 | + } else if (!curr_prog_id) { |
---|
| 64 | + printf("couldn't find a prog id on a %s\n", name); |
---|
| 65 | + } else { |
---|
| 66 | + printf("program on interface changed, not removing\n"); |
---|
| 67 | + } |
---|
42 | 68 | |
---|
43 | 69 | return err; |
---|
44 | 70 | } |
---|
45 | 71 | |
---|
46 | 72 | #define SAMPLE_SIZE 64 |
---|
47 | 73 | |
---|
48 | | -static int print_bpf_output(void *data, int size) |
---|
| 74 | +static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size) |
---|
49 | 75 | { |
---|
50 | 76 | struct { |
---|
51 | 77 | __u16 cookie; |
---|
.. | .. |
---|
55 | 81 | int i; |
---|
56 | 82 | |
---|
57 | 83 | if (e->cookie != 0xdead) { |
---|
58 | | - printf("BUG cookie %x sized %d\n", |
---|
59 | | - e->cookie, size); |
---|
60 | | - return LIBBPF_PERF_EVENT_ERROR; |
---|
| 84 | + printf("BUG cookie %x sized %d\n", e->cookie, size); |
---|
| 85 | + return; |
---|
61 | 86 | } |
---|
62 | 87 | |
---|
63 | 88 | printf("Pkt len: %-5d bytes. Ethernet hdr: ", e->pkt_len); |
---|
64 | 89 | for (i = 0; i < 14 && i < e->pkt_len; i++) |
---|
65 | 90 | printf("%02x ", e->pkt_data[i]); |
---|
66 | 91 | printf("\n"); |
---|
67 | | - |
---|
68 | | - return LIBBPF_PERF_EVENT_CONT; |
---|
69 | | -} |
---|
70 | | - |
---|
71 | | -static 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 | 92 | } |
---|
93 | 93 | |
---|
94 | 94 | static void sig_handler(int signo) |
---|
95 | 95 | { |
---|
96 | 96 | do_detach(if_idx, if_name); |
---|
| 97 | + perf_buffer__free(pb); |
---|
97 | 98 | exit(0); |
---|
| 99 | +} |
---|
| 100 | + |
---|
| 101 | +static void usage(const char *prog) |
---|
| 102 | +{ |
---|
| 103 | + fprintf(stderr, |
---|
| 104 | + "%s: %s [OPTS] <ifname|ifindex>\n\n" |
---|
| 105 | + "OPTS:\n" |
---|
| 106 | + " -F force loading prog\n", |
---|
| 107 | + __func__, prog); |
---|
98 | 108 | } |
---|
99 | 109 | |
---|
100 | 110 | int main(int argc, char **argv) |
---|
101 | 111 | { |
---|
| 112 | + struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; |
---|
102 | 113 | struct bpf_prog_load_attr prog_load_attr = { |
---|
103 | 114 | .prog_type = BPF_PROG_TYPE_XDP, |
---|
104 | 115 | }; |
---|
| 116 | + struct perf_buffer_opts pb_opts = {}; |
---|
| 117 | + const char *optstr = "FS"; |
---|
| 118 | + int prog_fd, map_fd, opt; |
---|
105 | 119 | struct bpf_object *obj; |
---|
106 | 120 | struct bpf_map *map; |
---|
107 | | - int prog_fd, map_fd; |
---|
108 | 121 | char filename[256]; |
---|
109 | | - int ret, err, i; |
---|
110 | | - int numcpus; |
---|
| 122 | + int ret, err; |
---|
111 | 123 | |
---|
112 | | - if (argc < 2) { |
---|
113 | | - printf("Usage: %s <ifname>\n", argv[0]); |
---|
| 124 | + while ((opt = getopt(argc, argv, optstr)) != -1) { |
---|
| 125 | + switch (opt) { |
---|
| 126 | + case 'F': |
---|
| 127 | + xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; |
---|
| 128 | + break; |
---|
| 129 | + case 'S': |
---|
| 130 | + xdp_flags |= XDP_FLAGS_SKB_MODE; |
---|
| 131 | + break; |
---|
| 132 | + default: |
---|
| 133 | + usage(basename(argv[0])); |
---|
| 134 | + return 1; |
---|
| 135 | + } |
---|
| 136 | + } |
---|
| 137 | + |
---|
| 138 | + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) |
---|
| 139 | + xdp_flags |= XDP_FLAGS_DRV_MODE; |
---|
| 140 | + |
---|
| 141 | + if (optind == argc) { |
---|
| 142 | + usage(basename(argv[0])); |
---|
114 | 143 | return 1; |
---|
115 | 144 | } |
---|
116 | 145 | |
---|
117 | | - numcpus = get_nprocs(); |
---|
118 | | - if (numcpus > MAX_CPUS) |
---|
119 | | - numcpus = MAX_CPUS; |
---|
| 146 | + if (setrlimit(RLIMIT_MEMLOCK, &r)) { |
---|
| 147 | + perror("setrlimit(RLIMIT_MEMLOCK)"); |
---|
| 148 | + return 1; |
---|
| 149 | + } |
---|
120 | 150 | |
---|
121 | 151 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
---|
122 | 152 | prog_load_attr.file = filename; |
---|
.. | .. |
---|
125 | 155 | return 1; |
---|
126 | 156 | |
---|
127 | 157 | if (!prog_fd) { |
---|
128 | | - printf("load_bpf_file: %s\n", strerror(errno)); |
---|
| 158 | + printf("bpf_prog_load_xattr: %s\n", strerror(errno)); |
---|
129 | 159 | return 1; |
---|
130 | 160 | } |
---|
131 | 161 | |
---|
.. | .. |
---|
136 | 166 | } |
---|
137 | 167 | map_fd = bpf_map__fd(map); |
---|
138 | 168 | |
---|
139 | | - if_idx = if_nametoindex(argv[1]); |
---|
| 169 | + if_idx = if_nametoindex(argv[optind]); |
---|
140 | 170 | if (!if_idx) |
---|
141 | | - if_idx = strtoul(argv[1], NULL, 0); |
---|
| 171 | + if_idx = strtoul(argv[optind], NULL, 0); |
---|
142 | 172 | |
---|
143 | 173 | if (!if_idx) { |
---|
144 | 174 | fprintf(stderr, "Invalid ifname\n"); |
---|
145 | 175 | return 1; |
---|
146 | 176 | } |
---|
147 | | - if_name = argv[1]; |
---|
148 | | - err = do_attach(if_idx, prog_fd, argv[1]); |
---|
| 177 | + if_name = argv[optind]; |
---|
| 178 | + err = do_attach(if_idx, prog_fd, if_name); |
---|
149 | 179 | if (err) |
---|
150 | 180 | return err; |
---|
151 | 181 | |
---|
.. | .. |
---|
156 | 186 | return 1; |
---|
157 | 187 | } |
---|
158 | 188 | |
---|
159 | | - test_bpf_perf_event(map_fd, numcpus); |
---|
| 189 | + pb_opts.sample_cb = print_bpf_output; |
---|
| 190 | + pb = perf_buffer__new(map_fd, 8, &pb_opts); |
---|
| 191 | + err = libbpf_get_error(pb); |
---|
| 192 | + if (err) { |
---|
| 193 | + perror("perf_buffer setup failed"); |
---|
| 194 | + return 1; |
---|
| 195 | + } |
---|
160 | 196 | |
---|
161 | | - for (i = 0; i < numcpus; i++) |
---|
162 | | - if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0) |
---|
163 | | - return 1; |
---|
| 197 | + while ((ret = perf_buffer__poll(pb, 1000)) >= 0) { |
---|
| 198 | + } |
---|
164 | 199 | |
---|
165 | | - ret = perf_event_poller_multi(pmu_fds, headers, numcpus, |
---|
166 | | - print_bpf_output); |
---|
167 | 200 | kill(0, SIGINT); |
---|
168 | 201 | return ret; |
---|
169 | 202 | } |
---|