2 * tc_bpf.c BPF common code
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Daniel Borkmann <dborkman@redhat.com>
10 * Jiri Pirko <jiri@resnulli.us>
11 * Alexei Starovoitov <ast@plumgrid.com>
22 #include <sys/types.h>
24 #include <linux/filter.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
37 int bpf_parse_string(char *arg
, bool from_file
, __u16
*bpf_len
,
38 char **bpf_string
, bool *need_release
,
44 size_t tmp_len
, op_len
= sizeof("65535 255 255 4294967295,");
48 tmp_len
= sizeof("4096,") + BPF_MAXINSNS
* op_len
;
49 tmp_string
= malloc(tmp_len
);
50 if (tmp_string
== NULL
)
53 memset(tmp_string
, 0, tmp_len
);
57 perror("Cannot fopen");
62 if (!fgets(tmp_string
, tmp_len
, fp
)) {
71 *bpf_string
= tmp_string
;
73 *need_release
= false;
77 if (sscanf(*bpf_string
, "%hu%c", bpf_len
, &sp
) != 2 ||
87 int bpf_parse_ops(int argc
, char **argv
, struct sock_filter
*bpf_ops
,
90 char *bpf_string
, *token
, separator
= ',';
97 if (bpf_parse_string(argv
[0], from_file
, &bpf_len
, &bpf_string
,
98 &need_release
, separator
))
100 if (bpf_len
== 0 || bpf_len
> BPF_MAXINSNS
) {
106 while ((token
= strchr(token
, separator
)) && (++token
)[0]) {
108 fprintf(stderr
, "Real program length exceeds encoded "
109 "length parameter!\n");
114 if (sscanf(token
, "%hu %hhu %hhu %u,",
115 &bpf_ops
[i
].code
, &bpf_ops
[i
].jt
,
116 &bpf_ops
[i
].jf
, &bpf_ops
[i
].k
) != 4) {
117 fprintf(stderr
, "Error at instruction %d!\n", i
);
126 fprintf(stderr
, "Parsed program length is less than encoded"
127 "length parameter!\n");
140 void bpf_print_ops(FILE *f
, struct rtattr
*bpf_ops
, __u16 len
)
142 struct sock_filter
*ops
= (struct sock_filter
*) RTA_DATA(bpf_ops
);
148 fprintf(f
, "bytecode \'%u,", len
);
150 for (i
= 0; i
< len
- 1; i
++)
151 fprintf(f
, "%hu %hhu %hhu %u,", ops
[i
].code
, ops
[i
].jt
,
152 ops
[i
].jf
, ops
[i
].k
);
154 fprintf(f
, "%hu %hhu %hhu %u\'\n", ops
[i
].code
, ops
[i
].jt
,
155 ops
[i
].jf
, ops
[i
].k
);
159 struct bpf_elf_sec_data
{
165 static char bpf_log_buf
[8192];
167 static const char *prog_type_section(enum bpf_prog_type type
)
170 case BPF_PROG_TYPE_SCHED_CLS
:
171 return ELF_SECTION_CLASSIFIER
;
172 /* case BPF_PROG_TYPE_SCHED_ACT: */
173 /* return ELF_SECTION_ACTION; */
179 static void bpf_dump_error(const char *format
, ...) __check_format_string(1, 2);
180 static void bpf_dump_error(const char *format
, ...)
184 va_start(vl
, format
);
185 vfprintf(stderr
, format
, vl
);
188 fprintf(stderr
, "%s", bpf_log_buf
);
189 memset(bpf_log_buf
, 0, sizeof(bpf_log_buf
));
192 static int bpf_create_map(enum bpf_map_type type
, unsigned int size_key
,
193 unsigned int size_value
, unsigned int max_elem
)
195 union bpf_attr attr
= {
197 .key_size
= size_key
,
198 .value_size
= size_value
,
199 .max_entries
= max_elem
,
202 return bpf(BPF_MAP_CREATE
, &attr
, sizeof(attr
));
205 static int bpf_prog_load(enum bpf_prog_type type
, const struct bpf_insn
*insns
,
206 unsigned int len
, const char *license
)
208 union bpf_attr attr
= {
210 .insns
= bpf_ptr_to_u64(insns
),
211 .insn_cnt
= len
/ sizeof(struct bpf_insn
),
212 .license
= bpf_ptr_to_u64(license
),
213 .log_buf
= bpf_ptr_to_u64(bpf_log_buf
),
214 .log_size
= sizeof(bpf_log_buf
),
218 return bpf(BPF_PROG_LOAD
, &attr
, sizeof(attr
));
221 static int bpf_prog_attach(enum bpf_prog_type type
, const struct bpf_insn
*insns
,
222 unsigned int size
, const char *license
)
224 int prog_fd
= bpf_prog_load(type
, insns
, size
, license
);
227 bpf_dump_error("BPF program rejected: %s\n", strerror(errno
));
232 static int bpf_map_attach(enum bpf_map_type type
, unsigned int size_key
,
233 unsigned int size_value
, unsigned int max_elem
)
235 int map_fd
= bpf_create_map(type
, size_key
, size_value
, max_elem
);
238 bpf_dump_error("BPF map rejected: %s\n", strerror(errno
));
243 static void bpf_maps_init(int *map_fds
, unsigned int max_fds
)
247 for (i
= 0; i
< max_fds
; i
++)
251 static void bpf_maps_destroy(const int *map_fds
, unsigned int max_fds
)
255 for (i
= 0; i
< max_fds
; i
++) {
261 static int bpf_maps_attach(struct bpf_elf_map
*maps
, unsigned int num_maps
,
262 int *map_fds
, unsigned int max_fds
)
266 for (i
= 0; i
< num_maps
&& num_maps
<= max_fds
; i
++) {
267 struct bpf_elf_map
*map
= &maps
[i
];
269 ret
= bpf_map_attach(map
->type
, map
->size_key
,
270 map
->size_value
, map
->max_elem
);
280 bpf_maps_destroy(map_fds
, i
);
284 static int bpf_fill_section_data(Elf
*elf_fd
, GElf_Ehdr
*elf_hdr
, int sec_index
,
285 struct bpf_elf_sec_data
*sec_data
)
292 memset(sec_data
, 0, sizeof(*sec_data
));
294 sec_fd
= elf_getscn(elf_fd
, sec_index
);
298 if (gelf_getshdr(sec_fd
, &sec_hdr
) != &sec_hdr
)
301 sec_name
= elf_strptr(elf_fd
, elf_hdr
->e_shstrndx
,
303 if (!sec_name
|| !sec_hdr
.sh_size
)
306 sec_edata
= elf_getdata(sec_fd
, NULL
);
307 if (!sec_edata
|| elf_getdata(sec_fd
, sec_edata
))
310 memcpy(&sec_data
->sec_hdr
, &sec_hdr
, sizeof(sec_hdr
));
311 sec_data
->sec_name
= sec_name
;
312 sec_data
->sec_data
= sec_edata
;
317 static int bpf_apply_relo_data(struct bpf_elf_sec_data
*data_relo
,
318 struct bpf_elf_sec_data
*data_insn
,
319 Elf_Data
*sym_tab
, int *map_fds
, int max_fds
)
321 Elf_Data
*idata
= data_insn
->sec_data
;
322 GElf_Shdr
*rhdr
= &data_relo
->sec_hdr
;
323 int relo_ent
, relo_num
= rhdr
->sh_size
/ rhdr
->sh_entsize
;
324 struct bpf_insn
*insns
= idata
->d_buf
;
325 unsigned int num_insns
= idata
->d_size
/ sizeof(*insns
);
327 for (relo_ent
= 0; relo_ent
< relo_num
; relo_ent
++) {
328 unsigned int ioff
, fnum
;
332 if (gelf_getrel(data_relo
->sec_data
, relo_ent
, &relo
) != &relo
)
335 ioff
= relo
.r_offset
/ sizeof(struct bpf_insn
);
336 if (ioff
>= num_insns
)
338 if (insns
[ioff
].code
!= (BPF_LD
| BPF_IMM
| BPF_DW
))
341 if (gelf_getsym(sym_tab
, GELF_R_SYM(relo
.r_info
), &sym
) != &sym
)
344 fnum
= sym
.st_value
/ sizeof(struct bpf_elf_map
);
348 insns
[ioff
].src_reg
= BPF_PSEUDO_MAP_FD
;
349 insns
[ioff
].imm
= map_fds
[fnum
];
355 static int bpf_fetch_ancillary(Elf
*elf_fd
, GElf_Ehdr
*elf_hdr
, bool *sec_seen
,
356 int *map_fds
, unsigned int max_fds
,
357 char *license
, unsigned int lic_len
,
360 int sec_index
, ret
= -1;
362 for (sec_index
= 1; sec_index
< elf_hdr
->e_shnum
; sec_index
++) {
363 struct bpf_elf_sec_data data_anc
;
365 ret
= bpf_fill_section_data(elf_fd
, elf_hdr
, sec_index
,
370 /* Extract and load eBPF map fds. */
371 if (!strcmp(data_anc
.sec_name
, ELF_SECTION_MAPS
)) {
372 struct bpf_elf_map
*maps
= data_anc
.sec_data
->d_buf
;
373 unsigned int maps_num
= data_anc
.sec_data
->d_size
/
376 sec_seen
[sec_index
] = true;
377 ret
= bpf_maps_attach(maps
, maps_num
, map_fds
,
382 /* Extract eBPF license. */
383 else if (!strcmp(data_anc
.sec_name
, ELF_SECTION_LICENSE
)) {
384 if (data_anc
.sec_data
->d_size
> lic_len
)
387 sec_seen
[sec_index
] = true;
388 memcpy(license
, data_anc
.sec_data
->d_buf
,
389 data_anc
.sec_data
->d_size
);
391 /* Extract symbol table for relocations (map fd fixups). */
392 else if (data_anc
.sec_hdr
.sh_type
== SHT_SYMTAB
) {
393 sec_seen
[sec_index
] = true;
394 *sym_tab
= data_anc
.sec_data
;
401 static int bpf_fetch_prog_relo(Elf
*elf_fd
, GElf_Ehdr
*elf_hdr
, bool *sec_seen
,
402 enum bpf_prog_type type
, char *license
,
403 Elf_Data
*sym_tab
, int *map_fds
, unsigned int max_fds
)
405 int sec_index
, prog_fd
= -1;
407 for (sec_index
= 1; sec_index
< elf_hdr
->e_shnum
; sec_index
++) {
408 struct bpf_elf_sec_data data_relo
, data_insn
;
411 /* Attach eBPF programs with relocation data (maps). */
412 ret
= bpf_fill_section_data(elf_fd
, elf_hdr
, sec_index
,
414 if (ret
< 0 || data_relo
.sec_hdr
.sh_type
!= SHT_REL
)
417 ins_index
= data_relo
.sec_hdr
.sh_info
;
419 ret
= bpf_fill_section_data(elf_fd
, elf_hdr
, ins_index
,
423 if (strcmp(data_insn
.sec_name
, prog_type_section(type
)))
426 sec_seen
[sec_index
] = true;
427 sec_seen
[ins_index
] = true;
429 ret
= bpf_apply_relo_data(&data_relo
, &data_insn
, sym_tab
,
434 prog_fd
= bpf_prog_attach(type
, data_insn
.sec_data
->d_buf
,
435 data_insn
.sec_data
->d_size
, license
);
445 static int bpf_fetch_prog(Elf
*elf_fd
, GElf_Ehdr
*elf_hdr
, bool *sec_seen
,
446 enum bpf_prog_type type
, char *license
)
448 int sec_index
, prog_fd
= -1;
450 for (sec_index
= 1; sec_index
< elf_hdr
->e_shnum
; sec_index
++) {
451 struct bpf_elf_sec_data data_insn
;
454 /* Attach eBPF programs without relocation data. */
455 if (sec_seen
[sec_index
])
458 ret
= bpf_fill_section_data(elf_fd
, elf_hdr
, sec_index
,
462 if (strcmp(data_insn
.sec_name
, prog_type_section(type
)))
465 prog_fd
= bpf_prog_attach(type
, data_insn
.sec_data
->d_buf
,
466 data_insn
.sec_data
->d_size
, license
);
476 int bpf_open_object(const char *path
, enum bpf_prog_type type
)
478 int map_fds
[ELF_MAX_MAPS
], max_fds
= ARRAY_SIZE(map_fds
);
479 char license
[ELF_MAX_LICENSE_LEN
];
480 int file_fd
, prog_fd
= -1, ret
;
481 Elf_Data
*sym_tab
= NULL
;
486 if (elf_version(EV_CURRENT
) == EV_NONE
)
489 file_fd
= open(path
, O_RDONLY
, 0);
493 elf_fd
= elf_begin(file_fd
, ELF_C_READ
, NULL
);
499 if (gelf_getehdr(elf_fd
, &elf_hdr
) != &elf_hdr
) {
504 sec_seen
= calloc(elf_hdr
.e_shnum
, sizeof(*sec_seen
));
510 memset(license
, 0, sizeof(license
));
511 bpf_maps_init(map_fds
, max_fds
);
513 ret
= bpf_fetch_ancillary(elf_fd
, &elf_hdr
, sec_seen
, map_fds
, max_fds
,
514 license
, sizeof(license
), &sym_tab
);
518 prog_fd
= bpf_fetch_prog_relo(elf_fd
, &elf_hdr
, sec_seen
, type
,
519 license
, sym_tab
, map_fds
, max_fds
);
521 prog_fd
= bpf_fetch_prog(elf_fd
, &elf_hdr
, sec_seen
, type
,
534 bpf_maps_destroy(map_fds
, max_fds
);
538 #endif /* HAVE_ELF */