[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1529225321-15429-1-git-send-email-ophirmu@mellanox.com>
Date: Sun, 17 Jun 2018 08:48:41 +0000
From: Ophir Munk <ophirmu@...lanox.com>
To: netdev@...r.kernel.org,
Stephen Hemminger <stephen@...workplumber.org>,
David Ahern <dsahern@...il.com>
Cc: Thomas Monjalon <thomas@...jalon.net>,
Olga Shern <olgas@...lanox.com>,
Ophir Munk <ophirmu@...lanox.com>
Subject: [PATCH] tc, bpf: add option to dump bpf verifier as C program fragment
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 <ophirmu@...lanox.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
Powered by blists - more mailing lists