Similar to cbpf used within tcpdump utility with a "-d" option to dump the compiled packet-matching code in a human readable form - tc has the "verbose" option to dump ebpf verifier output. Another useful option of cbpf using tcpdump "-dd" option is to dump packet-matching code a C program fragment. Similar to this - this commit adds a new tc ebpf option named "code" to dump ebpf verifier as C program fragment.
Existing "verbose" option sample output: Verifier analysis: 0: (61) r2 = *(u32 *)(r1 +52) 1: (18) r3 = 0xdeadbeef 3: (63) *(u32 *)(r10 -4) = r3 . . 11: (63) *(u32 *)(r1 +52) = r2 12: (18) r0 = 0xffffffff 14: (95) exit New "code" option sample output: /* struct bpf_insn cls_q_code[] = { */ {0x61, 2, 1, 52, 0x00000000}, {0x18, 3, 0, 0, 0xdeadbeef}, {0x00, 0, 0, 0, 0x00000000}, . . {0x63, 1, 2, 52, 0x00000000}, {0x18, 0, 0, 0, 0xffffffff}, {0x00, 0, 0, 0, 0x00000000}, {0x95, 0, 0, 0, 0x00000000}, Signed-off-by: Ophir Munk <ophi...@mellanox.com> --- include/bpf_util.h | 1 + lib/bpf.c | 35 +++++++++++++++++++++++++++++------ tc/m_bpf.c | 3 ++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index 219beb4..cf611c5 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -72,6 +72,7 @@ struct bpf_cfg_in { enum bpf_mode mode; __u32 ifindex; bool verbose; + bool code; int argc; char **argv; struct sock_filter opcodes[BPF_MAXINSNS]; diff --git a/lib/bpf.c b/lib/bpf.c index c38d92d..b13ec3f 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -113,10 +113,10 @@ const char *bpf_prog_to_default_section(enum bpf_prog_type type) #ifdef HAVE_ELF static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, __u32 ifindex, bool verbose); + const char *sec, __u32 ifindex, bool verbose, bool code); #else static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, __u32 ifindex, bool verbose) + const char *sec, __u32 ifindex, bool verbose, bool code) { fprintf(stderr, "No ELF library support compiled in.\n"); errno = ENOSYS; @@ -809,6 +809,7 @@ static int bpf_do_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) { const char *file, *section, *uds_name; bool verbose = false; + bool code = false; int i, ret, argc; char **argv; @@ -890,6 +891,11 @@ static int bpf_do_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) NEXT_ARG_FWD(); } + if (argc > 0 && matches(*argv, "code") == 0) { + code = true; + NEXT_ARG_FWD(); + } + PREV_ARG(); } @@ -911,6 +917,7 @@ static int bpf_do_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) cfg->uds = uds_name; cfg->argc = argc; cfg->argv = argv; + cfg->code = code; cfg->verbose = verbose; return ret; @@ -921,7 +928,7 @@ static int bpf_do_load(struct bpf_cfg_in *cfg) if (cfg->mode == EBPF_OBJECT) { cfg->prog_fd = bpf_obj_open(cfg->object, cfg->type, cfg->section, cfg->ifindex, - cfg->verbose); + cfg->verbose, cfg->code); return cfg->prog_fd; } return 0; @@ -1133,6 +1140,7 @@ struct bpf_elf_ctx { enum bpf_prog_type type; __u32 ifindex; bool verbose; + bool code; struct bpf_elf_st stat; struct bpf_hash_entry *ht[256]; char *log; @@ -1179,6 +1187,17 @@ bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...) } } +static void bpf_dump_code(const char *section, const struct bpf_insn *insns, unsigned int cnt) +{ + int i; + fprintf(stderr, "/* struct bpf_insn %s_code[] = { */\n", section); + for (i=0; i < cnt; i++) { + fprintf(stderr, "\t{0x%.2x, %4u, %4u, %8d, 0x%.8x},\n", + insns[i].code, insns[i].dst_reg, insns[i].src_reg, insns[i].off, insns[i].imm); + } + fprintf(stderr, "\n"); +} + static int bpf_log_realloc(struct bpf_elf_ctx *ctx) { const size_t log_max = UINT_MAX >> 8; @@ -1526,6 +1545,9 @@ retry: bpf_prog_report(fd, section, prog, ctx); } + if (ctx->code) + bpf_dump_code(section, prog->insns, prog->size / sizeof(struct bpf_insn)); + return fd; } @@ -2439,7 +2461,7 @@ static void bpf_get_cfg(struct bpf_elf_ctx *ctx) static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, enum bpf_prog_type type, __u32 ifindex, - bool verbose) + bool verbose, bool code) { int ret = -EINVAL; @@ -2450,6 +2472,7 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, memset(ctx, 0, sizeof(*ctx)); bpf_get_cfg(ctx); ctx->verbose = verbose; + ctx->code = code; ctx->type = type; ctx->ifindex = ifindex; @@ -2543,12 +2566,12 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) static struct bpf_elf_ctx __ctx; static int bpf_obj_open(const char *pathname, enum bpf_prog_type type, - const char *section, __u32 ifindex, bool verbose) + const char *section, __u32 ifindex, bool verbose, bool code) { struct bpf_elf_ctx *ctx = &__ctx; int fd = 0, ret; - ret = bpf_elf_ctx_init(ctx, pathname, type, ifindex, verbose); + ret = bpf_elf_ctx_init(ctx, pathname, type, ifindex, verbose, code); if (ret < 0) { fprintf(stderr, "Cannot initialize ELF context!\n"); return ret; diff --git a/tc/m_bpf.c b/tc/m_bpf.c index 1c1f71c..9947113 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -33,7 +33,8 @@ static void explain(void) fprintf(stderr, "\n"); fprintf(stderr, "eBPF use case:\n"); fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"); - fprintf(stderr, " [ verbose ]\n"); + fprintf(stderr, " [ verbose ]"); + fprintf(stderr, " [ code ]\n"); fprintf(stderr, " object-pinned FILE\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"); -- 1.8.3.1