Blame view

samples/bpf/bpf_load.c 16 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
249b812d8   Alexei Starovoitov   samples: bpf: elf...
2
3
4
5
6
7
8
9
10
11
  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <libelf.h>
  #include <gelf.h>
  #include <errno.h>
  #include <unistd.h>
  #include <string.h>
  #include <stdbool.h>
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
12
  #include <stdlib.h>
249b812d8   Alexei Starovoitov   samples: bpf: elf...
13
14
  #include <linux/bpf.h>
  #include <linux/filter.h>
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
15
  #include <linux/perf_event.h>
12d8bb64e   Martin KaFai Lau   bpf: xdp: Add XDP...
16
17
  #include <linux/netlink.h>
  #include <linux/rtnetlink.h>
6387d0111   Jesper Dangaard Brouer   samples/bpf: fix ...
18
  #include <linux/types.h>
12d8bb64e   Martin KaFai Lau   bpf: xdp: Add XDP...
19
  #include <sys/socket.h>
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
20
21
22
23
  #include <sys/syscall.h>
  #include <sys/ioctl.h>
  #include <sys/mman.h>
  #include <poll.h>
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
24
  #include <ctype.h>
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
25
  #include <assert.h>
2bf3e2ef4   Jakub Kicinski   samples: bpf: inc...
26
  #include <bpf/bpf.h>
249b812d8   Alexei Starovoitov   samples: bpf: elf...
27
  #include "bpf_load.h"
205c8ada3   Joe Stringer   samples/bpf: Remo...
28
  #include "perf-sys.h"
249b812d8   Alexei Starovoitov   samples: bpf: elf...
29

b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
30
  #define DEBUGFS "/sys/kernel/debug/tracing/"
249b812d8   Alexei Starovoitov   samples: bpf: elf...
31
  static char license[128];
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
32
  static int kern_version;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
33
  static bool processed_sec[128];
d40fc181e   Joe Stringer   samples/bpf: Make...
34
  char bpf_log_buf[BPF_LOG_BUF_SIZE];
249b812d8   Alexei Starovoitov   samples: bpf: elf...
35
36
  int map_fd[MAX_MAPS];
  int prog_fd[MAX_PROGS];
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
37
  int event_fd[MAX_PROGS];
249b812d8   Alexei Starovoitov   samples: bpf: elf...
38
  int prog_cnt;
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
39
  int prog_array_fd = -1;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
40
  struct bpf_map_data map_data[MAX_MAPS];
37b54aed1   Daniel T. Lee   samples/bpf: fix ...
41
  int map_data_count;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
42

5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
43
44
45
  static int populate_prog_array(const char *event, int prog_fd)
  {
  	int ind = atoi(event), err;
d40fc181e   Joe Stringer   samples/bpf: Make...
46
  	err = bpf_map_update_elem(prog_array_fd, &ind, &prog_fd, BPF_ANY);
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
47
48
49
50
51
52
53
  	if (err < 0) {
  		printf("failed to store prog_fd in prog_array
  ");
  		return -1;
  	}
  	return 0;
  }
249b812d8   Alexei Starovoitov   samples: bpf: elf...
54

5a8638132   Daniel T. Lee   samples: bpf: fix...
55
56
57
  static int write_kprobe_events(const char *val)
  {
  	int fd, ret, flags;
d59dd69d5   Daniel T. Lee   samples: bpf: fix...
58
59
60
  	if (val == NULL)
  		return -1;
  	else if (val[0] == '\0')
5a8638132   Daniel T. Lee   samples: bpf: fix...
61
62
63
  		flags = O_WRONLY | O_TRUNC;
  	else
  		flags = O_WRONLY | O_APPEND;
37b54aed1   Daniel T. Lee   samples/bpf: fix ...
64
  	fd = open(DEBUGFS "kprobe_events", flags);
5a8638132   Daniel T. Lee   samples: bpf: fix...
65
66
67
68
69
70
  
  	ret = write(fd, val, strlen(val));
  	close(fd);
  
  	return ret;
  }
249b812d8   Alexei Starovoitov   samples: bpf: elf...
71
72
  static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
  {
249b812d8   Alexei Starovoitov   samples: bpf: elf...
73
  	bool is_socket = strncmp(event, "socket", 6) == 0;
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
74
75
  	bool is_kprobe = strncmp(event, "kprobe/", 7) == 0;
  	bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
c07660409   Alexei Starovoitov   samples/bpf: add ...
76
  	bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0;
4662a4e53   Alexei Starovoitov   samples/bpf: raw ...
77
  	bool is_raw_tracepoint = strncmp(event, "raw_tracepoint/", 15) == 0;
86af8b419   Brenden Blanco   Add sample for ad...
78
  	bool is_xdp = strncmp(event, "xdp", 3) == 0;
1c47910ef   Alexei Starovoitov   samples/bpf: add ...
79
  	bool is_perf_event = strncmp(event, "perf_event", 10) == 0;
4f2e7ae56   David Ahern   samples/bpf: Upda...
80
81
  	bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0;
  	bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0;
40304b2a1   Lawrence Brakmo   bpf: BPF support ...
82
  	bool is_sockops = strncmp(event, "sockops", 7) == 0;
69e8cc134   John Fastabend   bpf: sockmap samp...
83
  	bool is_sk_skb = strncmp(event, "sk_skb", 6) == 0;
4c4c3c276   John Fastabend   bpf: sockmap samp...
84
  	bool is_sk_msg = strncmp(event, "sk_msg", 6) == 0;
43371c83f   Joe Stringer   samples/bpf: Swit...
85
  	size_t insns_cnt = size / sizeof(struct bpf_insn);
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  	enum bpf_prog_type prog_type;
  	char buf[256];
  	int fd, efd, err, id;
  	struct perf_event_attr attr = {};
  
  	attr.type = PERF_TYPE_TRACEPOINT;
  	attr.sample_type = PERF_SAMPLE_RAW;
  	attr.sample_period = 1;
  	attr.wakeup_events = 1;
  
  	if (is_socket) {
  		prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
  	} else if (is_kprobe || is_kretprobe) {
  		prog_type = BPF_PROG_TYPE_KPROBE;
c07660409   Alexei Starovoitov   samples/bpf: add ...
100
101
  	} else if (is_tracepoint) {
  		prog_type = BPF_PROG_TYPE_TRACEPOINT;
4662a4e53   Alexei Starovoitov   samples/bpf: raw ...
102
103
  	} else if (is_raw_tracepoint) {
  		prog_type = BPF_PROG_TYPE_RAW_TRACEPOINT;
86af8b419   Brenden Blanco   Add sample for ad...
104
105
  	} else if (is_xdp) {
  		prog_type = BPF_PROG_TYPE_XDP;
1c47910ef   Alexei Starovoitov   samples/bpf: add ...
106
107
  	} else if (is_perf_event) {
  		prog_type = BPF_PROG_TYPE_PERF_EVENT;
4f2e7ae56   David Ahern   samples/bpf: Upda...
108
109
110
111
  	} else if (is_cgroup_skb) {
  		prog_type = BPF_PROG_TYPE_CGROUP_SKB;
  	} else if (is_cgroup_sk) {
  		prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
40304b2a1   Lawrence Brakmo   bpf: BPF support ...
112
113
  	} else if (is_sockops) {
  		prog_type = BPF_PROG_TYPE_SOCK_OPS;
69e8cc134   John Fastabend   bpf: sockmap samp...
114
115
  	} else if (is_sk_skb) {
  		prog_type = BPF_PROG_TYPE_SK_SKB;
4c4c3c276   John Fastabend   bpf: sockmap samp...
116
117
  	} else if (is_sk_msg) {
  		prog_type = BPF_PROG_TYPE_SK_MSG;
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
118
119
120
  	} else {
  		printf("Unknown event '%s'
  ", event);
249b812d8   Alexei Starovoitov   samples: bpf: elf...
121
  		return -1;
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
122
  	}
b0294bc1a   Dan Carpenter   samples: bpf: ens...
123
124
  	if (prog_cnt == MAX_PROGS)
  		return -1;
43371c83f   Joe Stringer   samples/bpf: Swit...
125
  	fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version,
d40fc181e   Joe Stringer   samples/bpf: Make...
126
  			      bpf_log_buf, BPF_LOG_BUF_SIZE);
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
127
  	if (fd < 0) {
d40fc181e   Joe Stringer   samples/bpf: Make...
128
129
  		printf("bpf_load_program() err=%d
  %s", errno, bpf_log_buf);
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
130
131
132
133
  		return -1;
  	}
  
  	prog_fd[prog_cnt++] = fd;
4f2e7ae56   David Ahern   samples/bpf: Upda...
134
  	if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk)
86af8b419   Brenden Blanco   Add sample for ad...
135
  		return 0;
4c4c3c276   John Fastabend   bpf: sockmap samp...
136
  	if (is_socket || is_sockops || is_sk_skb || is_sk_msg) {
40304b2a1   Lawrence Brakmo   bpf: BPF support ...
137
138
139
140
  		if (is_socket)
  			event += 6;
  		else
  			event += 7;
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
141
142
143
144
145
146
147
148
149
150
  		if (*event != '/')
  			return 0;
  		event++;
  		if (!isdigit(*event)) {
  			printf("invalid prog number
  ");
  			return -1;
  		}
  		return populate_prog_array(event, fd);
  	}
4662a4e53   Alexei Starovoitov   samples/bpf: raw ...
151
152
153
154
155
156
157
158
159
160
  	if (is_raw_tracepoint) {
  		efd = bpf_raw_tracepoint_open(event + 15, fd);
  		if (efd < 0) {
  			printf("tracepoint %s %s
  ", event + 15, strerror(errno));
  			return -1;
  		}
  		event_fd[prog_cnt - 1] = efd;
  		return 0;
  	}
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
161
  	if (is_kprobe || is_kretprobe) {
34745aed5   Yonghong Song   samples/bpf: fix ...
162
163
  		bool need_normal_check = true;
  		const char *event_prefix = "";
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
164
165
166
167
  		if (is_kprobe)
  			event += 7;
  		else
  			event += 10;
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
168
169
170
171
172
173
174
175
  		if (*event == 0) {
  			printf("event name cannot be empty
  ");
  			return -1;
  		}
  
  		if (isdigit(*event))
  			return populate_prog_array(event, fd);
34745aed5   Yonghong Song   samples/bpf: fix ...
176
177
  #ifdef __x86_64__
  		if (strncmp(event, "sys_", 4) == 0) {
5a8638132   Daniel T. Lee   samples: bpf: fix...
178
179
180
  			snprintf(buf, sizeof(buf), "%c:__x64_%s __x64_%s",
  				is_kprobe ? 'p' : 'r', event, event);
  			err = write_kprobe_events(buf);
34745aed5   Yonghong Song   samples/bpf: fix ...
181
182
183
184
185
186
187
  			if (err >= 0) {
  				need_normal_check = false;
  				event_prefix = "__x64_";
  			}
  		}
  #endif
  		if (need_normal_check) {
5a8638132   Daniel T. Lee   samples: bpf: fix...
188
189
190
  			snprintf(buf, sizeof(buf), "%c:%s %s",
  				is_kprobe ? 'p' : 'r', event, event);
  			err = write_kprobe_events(buf);
34745aed5   Yonghong Song   samples/bpf: fix ...
191
192
193
194
195
196
  			if (err < 0) {
  				printf("failed to create kprobe '%s' error '%s'
  ",
  				       event, strerror(errno));
  				return -1;
  			}
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
197
  		}
249b812d8   Alexei Starovoitov   samples: bpf: elf...
198

c07660409   Alexei Starovoitov   samples/bpf: add ...
199
200
  		strcpy(buf, DEBUGFS);
  		strcat(buf, "events/kprobes/");
34745aed5   Yonghong Song   samples/bpf: fix ...
201
  		strcat(buf, event_prefix);
c07660409   Alexei Starovoitov   samples/bpf: add ...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  		strcat(buf, event);
  		strcat(buf, "/id");
  	} else if (is_tracepoint) {
  		event += 11;
  
  		if (*event == 0) {
  			printf("event name cannot be empty
  ");
  			return -1;
  		}
  		strcpy(buf, DEBUGFS);
  		strcat(buf, "events/");
  		strcat(buf, event);
  		strcat(buf, "/id");
  	}
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  
  	efd = open(buf, O_RDONLY, 0);
  	if (efd < 0) {
  		printf("failed to open event %s
  ", event);
  		return -1;
  	}
  
  	err = read(efd, buf, sizeof(buf));
  	if (err < 0 || err >= sizeof(buf)) {
  		printf("read from '%s' failed '%s'
  ", event, strerror(errno));
  		return -1;
  	}
  
  	close(efd);
  
  	buf[err] = 0;
  	id = atoi(buf);
  	attr.config = id;
205c8ada3   Joe Stringer   samples/bpf: Remo...
237
  	efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0);
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
238
239
240
241
242
243
  	if (efd < 0) {
  		printf("event %d fd %d err %s
  ", id, efd, strerror(errno));
  		return -1;
  	}
  	event_fd[prog_cnt - 1] = efd;
0ec9552b4   Yonghong Song   samples/bpf: add ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	err = ioctl(efd, PERF_EVENT_IOC_ENABLE, 0);
  	if (err < 0) {
  		printf("ioctl PERF_EVENT_IOC_ENABLE failed err %s
  ",
  		       strerror(errno));
  		return -1;
  	}
  	err = ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd);
  	if (err < 0) {
  		printf("ioctl PERF_EVENT_IOC_SET_BPF failed err %s
  ",
  		       strerror(errno));
  		return -1;
  	}
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
258

249b812d8   Alexei Starovoitov   samples: bpf: elf...
259
260
  	return 0;
  }
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
261
262
  static int load_maps(struct bpf_map_data *maps, int nr_maps,
  		     fixup_map_cb fixup_map)
249b812d8   Alexei Starovoitov   samples: bpf: elf...
263
  {
ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
264
  	int i, numa_node;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
265

5010e9484   Jesper Dangaard Brouer   samples/bpf: bpf_...
266
  	for (i = 0; i < nr_maps; i++) {
6979bcc73   Jesper Dangaard Brouer   samples/bpf: load...
267
268
269
270
271
272
273
274
  		if (fixup_map) {
  			fixup_map(&maps[i], i);
  			/* Allow userspace to assign map FD prior to creation */
  			if (maps[i].fd != -1) {
  				map_fd[i] = maps[i].fd;
  				continue;
  			}
  		}
249b812d8   Alexei Starovoitov   samples: bpf: elf...
275

ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
276
277
  		numa_node = maps[i].def.map_flags & BPF_F_NUMA_NODE ?
  			maps[i].def.numa_node : -1;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
278
279
280
  		if (maps[i].def.type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
  		    maps[i].def.type == BPF_MAP_TYPE_HASH_OF_MAPS) {
  			int inner_map_fd = map_fd[maps[i].def.inner_map_idx];
fb30d4b71   Martin KaFai Lau   bpf: Add tests fo...
281

ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
282
  			map_fd[i] = bpf_create_map_in_map_node(maps[i].def.type,
88cda1c9d   Martin KaFai Lau   bpf: libbpf: Prov...
283
  							maps[i].name,
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
284
285
286
  							maps[i].def.key_size,
  							inner_map_fd,
  							maps[i].def.max_entries,
ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
287
288
  							maps[i].def.map_flags,
  							numa_node);
fb30d4b71   Martin KaFai Lau   bpf: Add tests fo...
289
  		} else {
ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
290
  			map_fd[i] = bpf_create_map_node(maps[i].def.type,
88cda1c9d   Martin KaFai Lau   bpf: libbpf: Prov...
291
  							maps[i].name,
ad17d0e6c   Martin KaFai Lau   bpf: Allow numa s...
292
293
294
295
296
  							maps[i].def.key_size,
  							maps[i].def.value_size,
  							maps[i].def.max_entries,
  							maps[i].def.map_flags,
  							numa_node);
fb30d4b71   Martin KaFai Lau   bpf: Add tests fo...
297
  		}
618ec9a7b   Alexei Starovoitov   samples/bpf: make...
298
  		if (map_fd[i] < 0) {
bce6a1499   Shannon Nelson   bpf_load: add map...
299
300
301
  			printf("failed to create map %d (%s): %d %s
  ",
  			       i, maps[i].name, errno, strerror(errno));
249b812d8   Alexei Starovoitov   samples: bpf: elf...
302
  			return 1;
618ec9a7b   Alexei Starovoitov   samples/bpf: make...
303
  		}
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
304
  		maps[i].fd = map_fd[i];
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
305

156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
306
  		if (maps[i].def.type == BPF_MAP_TYPE_PROG_ARRAY)
5bacd7805   Alexei Starovoitov   samples/bpf: bpf_...
307
  			prog_array_fd = map_fd[i];
249b812d8   Alexei Starovoitov   samples: bpf: elf...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  	}
  	return 0;
  }
  
  static int get_sec(Elf *elf, int i, GElf_Ehdr *ehdr, char **shname,
  		   GElf_Shdr *shdr, Elf_Data **data)
  {
  	Elf_Scn *scn;
  
  	scn = elf_getscn(elf, i);
  	if (!scn)
  		return 1;
  
  	if (gelf_getshdr(scn, shdr) != shdr)
  		return 2;
  
  	*shname = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name);
  	if (!*shname || !shdr->sh_size)
  		return 3;
  
  	*data = elf_getdata(scn, 0);
  	if (!*data || elf_getdata(scn, *data) != NULL)
  		return 4;
  
  	return 0;
  }
  
  static int parse_relo_and_apply(Elf_Data *data, Elf_Data *symbols,
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
336
337
  				GElf_Shdr *shdr, struct bpf_insn *insn,
  				struct bpf_map_data *maps, int nr_maps)
249b812d8   Alexei Starovoitov   samples: bpf: elf...
338
339
340
341
342
343
344
345
346
  {
  	int i, nrels;
  
  	nrels = shdr->sh_size / shdr->sh_entsize;
  
  	for (i = 0; i < nrels; i++) {
  		GElf_Sym sym;
  		GElf_Rel rel;
  		unsigned int insn_idx;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
347
348
  		bool match = false;
  		int j, map_idx;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  
  		gelf_getrel(data, i, &rel);
  
  		insn_idx = rel.r_offset / sizeof(struct bpf_insn);
  
  		gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &sym);
  
  		if (insn[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
  			printf("invalid relo for insn[%d].code 0x%x
  ",
  			       insn_idx, insn[insn_idx].code);
  			return 1;
  		}
  		insn[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  
  		/* Match FD relocation against recorded map_data[] offset */
  		for (map_idx = 0; map_idx < nr_maps; map_idx++) {
  			if (maps[map_idx].elf_offset == sym.st_value) {
  				match = true;
  				break;
  			}
  		}
  		if (match) {
  			insn[insn_idx].imm = maps[map_idx].fd;
  		} else {
  			printf("invalid relo for insn[%d] no map_data match
  ",
  			       insn_idx);
  			return 1;
  		}
249b812d8   Alexei Starovoitov   samples: bpf: elf...
379
380
381
382
  	}
  
  	return 0;
  }
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
383
384
385
386
387
388
389
390
391
392
393
394
  static int cmp_symbols(const void *l, const void *r)
  {
  	const GElf_Sym *lsym = (const GElf_Sym *)l;
  	const GElf_Sym *rsym = (const GElf_Sym *)r;
  
  	if (lsym->st_value < rsym->st_value)
  		return -1;
  	else if (lsym->st_value > rsym->st_value)
  		return 1;
  	else
  		return 0;
  }
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
395
396
  static int load_elf_maps_section(struct bpf_map_data *maps, int maps_shndx,
  				 Elf *elf, Elf_Data *symbols, int strtabidx)
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
397
  {
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  	int map_sz_elf, map_sz_copy;
  	bool validate_zero = false;
  	Elf_Data *data_maps;
  	int i, nr_maps;
  	GElf_Sym *sym;
  	Elf_Scn *scn;
  	int copy_sz;
  
  	if (maps_shndx < 0)
  		return -EINVAL;
  	if (!symbols)
  		return -EINVAL;
  
  	/* Get data for maps section via elf index */
  	scn = elf_getscn(elf, maps_shndx);
  	if (scn)
  		data_maps = elf_getdata(scn, NULL);
  	if (!scn || !data_maps) {
  		printf("Failed to get Elf_Data from maps section %d
  ",
  		       maps_shndx);
  		return -EINVAL;
  	}
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
421

156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
422
423
424
425
426
  	/* For each map get corrosponding symbol table entry */
  	sym = calloc(MAX_MAPS+1, sizeof(GElf_Sym));
  	for (i = 0, nr_maps = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
  		assert(nr_maps < MAX_MAPS+1);
  		if (!gelf_getsym(symbols, i, &sym[nr_maps]))
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
427
  			continue;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
428
  		if (sym[nr_maps].st_shndx != maps_shndx)
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
429
  			continue;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
430
  		/* Only increment iif maps section */
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
431
432
  		nr_maps++;
  	}
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
433
434
435
436
437
  	/* Align to map_fd[] order, via sort on offset in sym.st_value */
  	qsort(sym, nr_maps, sizeof(GElf_Sym), cmp_symbols);
  
  	/* Keeping compatible with ELF maps section changes
  	 * ------------------------------------------------
74662ea5d   Jakub Kicinski   samples: bpf: ren...
438
  	 * The program size of struct bpf_load_map_def is known by loader
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
439
440
441
442
443
444
445
446
  	 * code, but struct stored in ELF file can be different.
  	 *
  	 * Unfortunately sym[i].st_size is zero.  To calculate the
  	 * struct size stored in the ELF file, assume all struct have
  	 * the same size, and simply divide with number of map
  	 * symbols.
  	 */
  	map_sz_elf = data_maps->d_size / nr_maps;
74662ea5d   Jakub Kicinski   samples: bpf: ren...
447
  	map_sz_copy = sizeof(struct bpf_load_map_def);
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  	if (map_sz_elf < map_sz_copy) {
  		/*
  		 * Backward compat, loading older ELF file with
  		 * smaller struct, keeping remaining bytes zero.
  		 */
  		map_sz_copy = map_sz_elf;
  	} else if (map_sz_elf > map_sz_copy) {
  		/*
  		 * Forward compat, loading newer ELF file with larger
  		 * struct with unknown features. Assume zero means
  		 * feature not used.  Thus, validate rest of struct
  		 * data is zero.
  		 */
  		validate_zero = true;
  	}
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
463

156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
464
  	/* Memcpy relevant part of ELF maps data to loader maps */
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
465
  	for (i = 0; i < nr_maps; i++) {
74662ea5d   Jakub Kicinski   samples: bpf: ren...
466
  		struct bpf_load_map_def *def;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
467
  		unsigned char *addr, *end;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
468
469
470
471
472
473
  		const char *map_name;
  		size_t offset;
  
  		map_name = elf_strptr(elf, strtabidx, sym[i].st_name);
  		maps[i].name = strdup(map_name);
  		if (!maps[i].name) {
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
474
475
476
  			printf("strdup(%s): %s(%d)
  ", map_name,
  			       strerror(errno), errno);
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
477
478
479
480
481
482
  			free(sym);
  			return -errno;
  		}
  
  		/* Symbol value is offset into ELF maps section data area */
  		offset = sym[i].st_value;
74662ea5d   Jakub Kicinski   samples: bpf: ren...
483
  		def = (struct bpf_load_map_def *)(data_maps->d_buf + offset);
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
484
  		maps[i].elf_offset = offset;
74662ea5d   Jakub Kicinski   samples: bpf: ren...
485
  		memset(&maps[i].def, 0, sizeof(struct bpf_load_map_def));
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
486
487
488
489
  		memcpy(&maps[i].def, def, map_sz_copy);
  
  		/* Verify no newer features were requested */
  		if (validate_zero) {
37b54aed1   Daniel T. Lee   samples/bpf: fix ...
490
491
  			addr = (unsigned char *) def + map_sz_copy;
  			end  = (unsigned char *) def + map_sz_elf;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
492
493
494
495
496
497
  			for (; addr < end; addr++) {
  				if (*addr != 0) {
  					free(sym);
  					return -EFBIG;
  				}
  			}
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
498
499
  		}
  	}
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
500
  	free(sym);
5010e9484   Jesper Dangaard Brouer   samples/bpf: bpf_...
501
  	return nr_maps;
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
502
503
504
  }
  
  static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map)
249b812d8   Alexei Starovoitov   samples: bpf: elf...
505
  {
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
506
  	int fd, i, ret, maps_shndx = -1, strtabidx = -1;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
507
508
509
  	Elf *elf;
  	GElf_Ehdr ehdr;
  	GElf_Shdr shdr, shdr_prog;
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
510
  	Elf_Data *data, *data_prog, *data_maps = NULL, *symbols = NULL;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
511
512
  	char *shname, *shname_prog;
  	int nr_maps = 0;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
513

a734fb5d6   Mickaël Salaün   samples/bpf: Rese...
514
515
516
517
  	/* reset global variables */
  	kern_version = 0;
  	memset(license, 0, sizeof(license));
  	memset(processed_sec, 0, sizeof(processed_sec));
249b812d8   Alexei Starovoitov   samples: bpf: elf...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  	if (elf_version(EV_CURRENT) == EV_NONE)
  		return 1;
  
  	fd = open(path, O_RDONLY, 0);
  	if (fd < 0)
  		return 1;
  
  	elf = elf_begin(fd, ELF_C_READ, NULL);
  
  	if (!elf)
  		return 1;
  
  	if (gelf_getehdr(elf, &ehdr) != &ehdr)
  		return 1;
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
532
  	/* clear all kprobes */
5a8638132   Daniel T. Lee   samples: bpf: fix...
533
  	i = write_kprobe_events("");
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
534

249b812d8   Alexei Starovoitov   samples: bpf: elf...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  	/* scan over all elf sections to get license and map info */
  	for (i = 1; i < ehdr.e_shnum; i++) {
  
  		if (get_sec(elf, i, &ehdr, &shname, &shdr, &data))
  			continue;
  
  		if (0) /* helpful for llvm debugging */
  			printf("section %d:%s data %p size %zd link %d flags %d
  ",
  			       i, shname, data->d_buf, data->d_size,
  			       shdr.sh_link, (int) shdr.sh_flags);
  
  		if (strcmp(shname, "license") == 0) {
  			processed_sec[i] = true;
  			memcpy(license, data->d_buf, data->d_size);
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
550
551
552
553
554
555
556
557
558
  		} else if (strcmp(shname, "version") == 0) {
  			processed_sec[i] = true;
  			if (data->d_size != sizeof(int)) {
  				printf("invalid size of version section %zd
  ",
  				       data->d_size);
  				return 1;
  			}
  			memcpy(&kern_version, data->d_buf, sizeof(int));
249b812d8   Alexei Starovoitov   samples: bpf: elf...
559
  		} else if (strcmp(shname, "maps") == 0) {
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
560
  			int j;
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
561
562
  			maps_shndx = i;
  			data_maps = data;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
563
564
  			for (j = 0; j < MAX_MAPS; j++)
  				map_data[j].fd = -1;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
565
  		} else if (shdr.sh_type == SHT_SYMTAB) {
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
566
  			strtabidx = shdr.sh_link;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
567
568
569
  			symbols = data;
  		}
  	}
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
570
571
572
573
574
575
576
577
578
  	ret = 1;
  
  	if (!symbols) {
  		printf("missing SHT_SYMTAB section
  ");
  		goto done;
  	}
  
  	if (data_maps) {
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
579
580
581
582
583
584
  		nr_maps = load_elf_maps_section(map_data, maps_shndx,
  						elf, symbols, strtabidx);
  		if (nr_maps < 0) {
  			printf("Error: Failed loading ELF maps (errno:%d):%s
  ",
  			       nr_maps, strerror(-nr_maps));
5010e9484   Jesper Dangaard Brouer   samples/bpf: bpf_...
585
586
  			goto done;
  		}
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
587
  		if (load_maps(map_data, nr_maps, fixup_map))
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
588
  			goto done;
156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
589
  		map_data_count = nr_maps;
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
590
591
592
  
  		processed_sec[maps_shndx] = true;
  	}
7bc57950b   Jesper Dangaard Brouer   samples/bpf: bpf_...
593
  	/* process all relo sections, and rewrite bpf insns for maps */
249b812d8   Alexei Starovoitov   samples: bpf: elf...
594
  	for (i = 1; i < ehdr.e_shnum; i++) {
16ad13290   Mickaël Salaün   samples/bpf: Igno...
595
596
  		if (processed_sec[i])
  			continue;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
597
598
599
  
  		if (get_sec(elf, i, &ehdr, &shname, &shdr, &data))
  			continue;
7bc57950b   Jesper Dangaard Brouer   samples/bpf: bpf_...
600

249b812d8   Alexei Starovoitov   samples: bpf: elf...
601
602
  		if (shdr.sh_type == SHT_REL) {
  			struct bpf_insn *insns;
7bc57950b   Jesper Dangaard Brouer   samples/bpf: bpf_...
603
  			/* locate prog sec that need map fixup (relocations) */
249b812d8   Alexei Starovoitov   samples: bpf: elf...
604
605
606
  			if (get_sec(elf, shdr.sh_info, &ehdr, &shname_prog,
  				    &shdr_prog, &data_prog))
  				continue;
db6a71dd9   Alexei Starovoitov   samples/bpf: fix ...
607
608
609
  			if (shdr_prog.sh_type != SHT_PROGBITS ||
  			    !(shdr_prog.sh_flags & SHF_EXECINSTR))
  				continue;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
610
  			insns = (struct bpf_insn *) data_prog->d_buf;
7bc57950b   Jesper Dangaard Brouer   samples/bpf: bpf_...
611
  			processed_sec[i] = true; /* relo section */
249b812d8   Alexei Starovoitov   samples: bpf: elf...
612

156450d9d   Jesper Dangaard Brouer   samples/bpf: make...
613
614
  			if (parse_relo_and_apply(data, symbols, &shdr, insns,
  						 map_data, nr_maps))
249b812d8   Alexei Starovoitov   samples: bpf: elf...
615
  				continue;
249b812d8   Alexei Starovoitov   samples: bpf: elf...
616
617
  		}
  	}
7bc57950b   Jesper Dangaard Brouer   samples/bpf: bpf_...
618
  	/* load programs */
249b812d8   Alexei Starovoitov   samples: bpf: elf...
619
620
621
622
623
624
625
  	for (i = 1; i < ehdr.e_shnum; i++) {
  
  		if (processed_sec[i])
  			continue;
  
  		if (get_sec(elf, i, &ehdr, &shname, &shdr, &data))
  			continue;
b896c4f95   Alexei Starovoitov   samples/bpf: Add ...
626
627
  		if (memcmp(shname, "kprobe/", 7) == 0 ||
  		    memcmp(shname, "kretprobe/", 10) == 0 ||
c07660409   Alexei Starovoitov   samples/bpf: add ...
628
  		    memcmp(shname, "tracepoint/", 11) == 0 ||
4662a4e53   Alexei Starovoitov   samples/bpf: raw ...
629
  		    memcmp(shname, "raw_tracepoint/", 15) == 0 ||
86af8b419   Brenden Blanco   Add sample for ad...
630
  		    memcmp(shname, "xdp", 3) == 0 ||
1c47910ef   Alexei Starovoitov   samples/bpf: add ...
631
  		    memcmp(shname, "perf_event", 10) == 0 ||
4f2e7ae56   David Ahern   samples/bpf: Upda...
632
  		    memcmp(shname, "socket", 6) == 0 ||
40304b2a1   Lawrence Brakmo   bpf: BPF support ...
633
  		    memcmp(shname, "cgroup/", 7) == 0 ||
69e8cc134   John Fastabend   bpf: sockmap samp...
634
  		    memcmp(shname, "sockops", 7) == 0 ||
4c4c3c276   John Fastabend   bpf: sockmap samp...
635
636
  		    memcmp(shname, "sk_skb", 6) == 0 ||
  		    memcmp(shname, "sk_msg", 6) == 0) {
f856e4697   Lawrence Brakmo   bpf: fix return i...
637
638
639
640
641
  			ret = load_and_attach(shname, data->d_buf,
  					      data->d_size);
  			if (ret != 0)
  				goto done;
  		}
249b812d8   Alexei Starovoitov   samples: bpf: elf...
642
  	}
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
643
  done:
249b812d8   Alexei Starovoitov   samples: bpf: elf...
644
  	close(fd);
9fd63d05f   Martin KaFai Lau   bpf: Allow bpf sa...
645
646
647
648
649
650
651
652
653
654
655
  	return ret;
  }
  
  int load_bpf_file(char *path)
  {
  	return do_load_bpf_file(path, NULL);
  }
  
  int load_bpf_file_fixup_map(const char *path, fixup_map_cb fixup_map)
  {
  	return do_load_bpf_file(path, fixup_map);
249b812d8   Alexei Starovoitov   samples: bpf: elf...
656
  }