tc: {m, f}_ebpf: add option for dumping verifier log
Currently, only on error we get a log dump, but I found it useful when working with eBPF to have an option to also dump the log on success. Also spotted a typo in a header comment, which is fixed here as well. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Cc: Alexei Starovoitov <ast@plumgrid.com> Acked-by: Alexei Starovoitov <ast@plumgrid.com>
This commit is contained in:
parent
d7bd2db52c
commit
d937a74b6d
14
tc/f_bpf.c
14
tc/f_bpf.c
|
|
@ -40,7 +40,8 @@ static void explain(void)
|
||||||
fprintf(stderr, " bytecode-file FILE\n");
|
fprintf(stderr, " bytecode-file FILE\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "eBPF use case:\n");
|
fprintf(stderr, "eBPF use case:\n");
|
||||||
fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]\n");
|
fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
|
||||||
|
fprintf(stderr, " [ verbose ]\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "Common remaining options:\n");
|
fprintf(stderr, "Common remaining options:\n");
|
||||||
fprintf(stderr, " [ action ACTION_SPEC ]\n");
|
fprintf(stderr, " [ action ACTION_SPEC ]\n");
|
||||||
|
|
@ -94,12 +95,13 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if (matches(*argv, "run") == 0) {
|
if (matches(*argv, "run") == 0) {
|
||||||
struct sock_filter bpf_ops[BPF_MAXINSNS];
|
struct sock_filter bpf_ops[BPF_MAXINSNS];
|
||||||
bool from_file, ebpf;
|
bool from_file, ebpf, bpf_verbose;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
opt_bpf:
|
opt_bpf:
|
||||||
bpf_sec_name = bpf_default_section(bpf_type);
|
bpf_sec_name = bpf_default_section(bpf_type);
|
||||||
|
bpf_verbose = false;
|
||||||
ebpf = false;
|
ebpf = false;
|
||||||
seen_run = true;
|
seen_run = true;
|
||||||
|
|
||||||
|
|
@ -135,11 +137,17 @@ opt_bpf:
|
||||||
bpf_uds_name = *argv;
|
bpf_uds_name = *argv;
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
}
|
||||||
|
if (strcmp(*argv, "verbose") == 0 ||
|
||||||
|
strcmp(*argv, "verb") == 0) {
|
||||||
|
bpf_verbose = true;
|
||||||
|
NEXT_ARG();
|
||||||
|
}
|
||||||
|
|
||||||
PREV_ARG();
|
PREV_ARG();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name) :
|
ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name,
|
||||||
|
bpf_verbose) :
|
||||||
bpf_parse_ops(argc, argv, bpf_ops, from_file);
|
bpf_parse_ops(argc, argv, bpf_ops, from_file);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "%s\n", ebpf ?
|
fprintf(stderr, "%s\n", ebpf ?
|
||||||
|
|
|
||||||
16
tc/m_bpf.c
16
tc/m_bpf.c
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* m_bpf.c BFP based action module
|
* m_bpf.c BPF based action module
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -35,7 +35,8 @@ static void explain(void)
|
||||||
fprintf(stderr, " bytecode-file FILE\n");
|
fprintf(stderr, " bytecode-file FILE\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "eBPF use case:\n");
|
fprintf(stderr, "eBPF use case:\n");
|
||||||
fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]\n");
|
fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]");
|
||||||
|
fprintf(stderr, " [ verbose ]\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
|
fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
|
||||||
fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
|
fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
|
||||||
|
|
@ -78,12 +79,13 @@ static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if (matches(*argv, "run") == 0) {
|
if (matches(*argv, "run") == 0) {
|
||||||
bool from_file;
|
bool from_file, bpf_verbose;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
opt_bpf:
|
opt_bpf:
|
||||||
bpf_sec_name = bpf_default_section(bpf_type);
|
bpf_sec_name = bpf_default_section(bpf_type);
|
||||||
|
bpf_verbose = false;
|
||||||
seen_run = true;
|
seen_run = true;
|
||||||
|
|
||||||
if (strcmp(*argv, "bytecode-file") == 0 ||
|
if (strcmp(*argv, "bytecode-file") == 0 ||
|
||||||
|
|
@ -118,11 +120,17 @@ opt_bpf:
|
||||||
bpf_uds_name = *argv;
|
bpf_uds_name = *argv;
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
}
|
||||||
|
if (strcmp(*argv, "verbose") == 0 ||
|
||||||
|
strcmp(*argv, "verb") == 0) {
|
||||||
|
bpf_verbose = true;
|
||||||
|
NEXT_ARG();
|
||||||
|
}
|
||||||
|
|
||||||
PREV_ARG();
|
PREV_ARG();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name) :
|
ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name,
|
||||||
|
bpf_verbose) :
|
||||||
bpf_parse_ops(argc, argv, bpf_ops, from_file);
|
bpf_parse_ops(argc, argv, bpf_ops, from_file);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "%s\n", ebpf ?
|
fprintf(stderr, "%s\n", ebpf ?
|
||||||
|
|
|
||||||
19
tc/tc_bpf.c
19
tc/tc_bpf.c
|
|
@ -192,6 +192,7 @@ struct bpf_map_data {
|
||||||
* verifier we still want to hand something descriptive to the user.
|
* verifier we still want to hand something descriptive to the user.
|
||||||
*/
|
*/
|
||||||
static char bpf_log_buf[65536];
|
static char bpf_log_buf[65536];
|
||||||
|
static bool bpf_verbose;
|
||||||
|
|
||||||
static struct bpf_elf_st bpf_st;
|
static struct bpf_elf_st bpf_st;
|
||||||
|
|
||||||
|
|
@ -207,8 +208,10 @@ static void bpf_dump_error(const char *format, ...)
|
||||||
vfprintf(stderr, format, vl);
|
vfprintf(stderr, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
fprintf(stderr, "%s\n", bpf_log_buf);
|
if (bpf_log_buf[0]) {
|
||||||
memset(bpf_log_buf, 0, sizeof(bpf_log_buf));
|
fprintf(stderr, "%s\n", bpf_log_buf);
|
||||||
|
memset(bpf_log_buf, 0, sizeof(bpf_log_buf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bpf_save_finfo(int file_fd)
|
static void bpf_save_finfo(int file_fd)
|
||||||
|
|
@ -284,8 +287,11 @@ static int bpf_prog_attach(enum bpf_prog_type type, const struct bpf_insn *insns
|
||||||
{
|
{
|
||||||
int prog_fd = bpf_prog_load(type, insns, size, license);
|
int prog_fd = bpf_prog_load(type, insns, size, license);
|
||||||
|
|
||||||
if (prog_fd < 0)
|
if (prog_fd < 0 || bpf_verbose) {
|
||||||
bpf_dump_error("BPF program rejected: %s\n", strerror(errno));
|
bpf_dump_error("%s: %s\n", prog_fd < 0 ?
|
||||||
|
"BPF program rejected" :
|
||||||
|
"BPF program verification", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
return prog_fd;
|
return prog_fd;
|
||||||
}
|
}
|
||||||
|
|
@ -555,7 +561,8 @@ static int bpf_fetch_prog(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen,
|
||||||
return prog_fd;
|
return prog_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_open_object(const char *path, enum bpf_prog_type type, const char *sec)
|
int bpf_open_object(const char *path, enum bpf_prog_type type,
|
||||||
|
const char *sec, bool verbose)
|
||||||
{
|
{
|
||||||
char license[ELF_MAX_LICENSE_LEN];
|
char license[ELF_MAX_LICENSE_LEN];
|
||||||
int file_fd, prog_fd = -1, ret;
|
int file_fd, prog_fd = -1, ret;
|
||||||
|
|
@ -589,6 +596,8 @@ int bpf_open_object(const char *path, enum bpf_prog_type type, const char *sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(license, 0, sizeof(license));
|
memset(license, 0, sizeof(license));
|
||||||
|
bpf_verbose = verbose;
|
||||||
|
|
||||||
if (!bpf_may_skip_map_creation(file_fd))
|
if (!bpf_may_skip_map_creation(file_fd))
|
||||||
bpf_maps_init();
|
bpf_maps_init();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const char *bpf_default_section(const enum bpf_prog_type type);
|
||||||
|
|
||||||
#ifdef HAVE_ELF
|
#ifdef HAVE_ELF
|
||||||
int bpf_open_object(const char *path, enum bpf_prog_type type,
|
int bpf_open_object(const char *path, enum bpf_prog_type type,
|
||||||
const char *sec);
|
const char *sec, bool verbose);
|
||||||
|
|
||||||
int bpf_send_map_fds(const char *path, const char *obj);
|
int bpf_send_map_fds(const char *path, const char *obj);
|
||||||
int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux,
|
int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux,
|
||||||
|
|
@ -59,7 +59,7 @@ static inline int bpf(int cmd, union bpf_attr *attr, unsigned int size)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline int bpf_open_object(const char *path, enum bpf_prog_type type,
|
static inline int bpf_open_object(const char *path, enum bpf_prog_type type,
|
||||||
const char *sec)
|
const char *sec, bool verbose)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "No ELF library support compiled in.\n");
|
fprintf(stderr, "No ELF library support compiled in.\n");
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue