Commit a8e8c0ec authored by David S. Miller's avatar David S. Miller

Merge branch 'bpftool-add-a-version-command-and-fix-several-items'

Jakub Kicinski says:

====================
tools: bpftool: add a "version" command, and fix several items

Quentin says:

The first seven patches of this series bring several minor fixes to
bpftool. Please see individual commit logs for details.

Last patch adds a "version" commands to bpftool, which is in fact the
version of the kernel from which it was compiled.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f3ae608e 821cfbb0
...@@ -11,8 +11,8 @@ SYNOPSIS ...@@ -11,8 +11,8 @@ SYNOPSIS
======== ========
| **bpftool** prog show [*PROG*] | **bpftool** prog show [*PROG*]
| **bpftool** prog dump xlated *PROG* [file *FILE*] [opcodes] | **bpftool** prog dump xlated *PROG* [{file *FILE* | opcodes }]
| **bpftool** prog dump jited *PROG* [file *FILE*] [opcodes] | **bpftool** prog dump jited *PROG* [{file *FILE* | opcodes }]
| **bpftool** prog pin *PROG* *FILE* | **bpftool** prog pin *PROG* *FILE*
| **bpftool** prog help | **bpftool** prog help
| |
...@@ -28,14 +28,14 @@ DESCRIPTION ...@@ -28,14 +28,14 @@ DESCRIPTION
Output will start with program ID followed by program type and Output will start with program ID followed by program type and
zero or more named attributes (depending on kernel version). zero or more named attributes (depending on kernel version).
**bpftool prog dump xlated** *PROG* [**file** *FILE*] [**opcodes**] **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** }]
Dump eBPF instructions of the program from the kernel. Dump eBPF instructions of the program from the kernel.
If *FILE* is specified image will be written to a file, If *FILE* is specified image will be written to a file,
otherwise it will be disassembled and printed to stdout. otherwise it will be disassembled and printed to stdout.
**opcodes** controls if raw opcodes will be printed. **opcodes** controls if raw opcodes will be printed.
**bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**] **bpftool prog dump jited** *PROG* [{ **file** *FILE* | **opcodes** }]
Dump jited image (host machine code) of the program. Dump jited image (host machine code) of the program.
If *FILE* is specified image will be written to a file, If *FILE* is specified image will be written to a file,
otherwise it will be disassembled and printed to stdout. otherwise it will be disassembled and printed to stdout.
......
...@@ -14,6 +14,8 @@ SYNOPSIS ...@@ -14,6 +14,8 @@ SYNOPSIS
**bpftool** batch file *FILE* **bpftool** batch file *FILE*
**bpftool** version
*OBJECT* := { **map** | **program** } *OBJECT* := { **map** | **program** }
*MAP-COMMANDS* := *MAP-COMMANDS* :=
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/version.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
...@@ -62,13 +63,23 @@ static int do_help(int argc, char **argv) ...@@ -62,13 +63,23 @@ static int do_help(int argc, char **argv)
fprintf(stderr, fprintf(stderr,
"Usage: %s OBJECT { COMMAND | help }\n" "Usage: %s OBJECT { COMMAND | help }\n"
" %s batch file FILE\n" " %s batch file FILE\n"
" %s version\n"
"\n" "\n"
" OBJECT := { prog | map }\n", " OBJECT := { prog | map }\n",
bin_name, bin_name); bin_name, bin_name, bin_name);
return 0; return 0;
} }
static int do_version(int argc, char **argv)
{
printf("%s v%d.%d.%d\n", bin_name,
LINUX_VERSION_CODE >> 16,
LINUX_VERSION_CODE >> 8 & 0xf,
LINUX_VERSION_CODE & 0xf);
return 0;
}
int cmd_select(const struct cmd *cmds, int argc, char **argv, int cmd_select(const struct cmd *cmds, int argc, char **argv,
int (*help)(int argc, char **argv)) int (*help)(int argc, char **argv))
{ {
...@@ -100,7 +111,7 @@ bool is_prefix(const char *pfx, const char *str) ...@@ -100,7 +111,7 @@ bool is_prefix(const char *pfx, const char *str)
return !memcmp(str, pfx, strlen(pfx)); return !memcmp(str, pfx, strlen(pfx));
} }
void print_hex(void *arg, unsigned int n, const char *sep) void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
{ {
unsigned char *data = arg; unsigned char *data = arg;
unsigned int i; unsigned int i;
...@@ -111,13 +122,13 @@ void print_hex(void *arg, unsigned int n, const char *sep) ...@@ -111,13 +122,13 @@ void print_hex(void *arg, unsigned int n, const char *sep)
if (!i) if (!i)
/* nothing */; /* nothing */;
else if (!(i % 16)) else if (!(i % 16))
printf("\n"); fprintf(f, "\n");
else if (!(i % 8)) else if (!(i % 8))
printf(" "); fprintf(f, " ");
else else
pfx = sep; pfx = sep;
printf("%s%02hhx", i ? pfx : "", data[i]); fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
} }
} }
...@@ -128,6 +139,7 @@ static const struct cmd cmds[] = { ...@@ -128,6 +139,7 @@ static const struct cmd cmds[] = {
{ "batch", do_batch }, { "batch", do_batch },
{ "prog", do_prog }, { "prog", do_prog },
{ "map", do_map }, { "map", do_map },
{ "version", do_version },
{ 0 } { 0 }
}; };
......
...@@ -67,7 +67,7 @@ enum bpf_obj_type { ...@@ -67,7 +67,7 @@ enum bpf_obj_type {
extern const char *bin_name; extern const char *bin_name;
bool is_prefix(const char *pfx, const char *str); bool is_prefix(const char *pfx, const char *str);
void print_hex(void *arg, unsigned int n, const char *sep); void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
void usage(void) __attribute__((noreturn)); void usage(void) __attribute__((noreturn));
struct cmd { struct cmd {
......
...@@ -216,12 +216,12 @@ static void print_entry(struct bpf_map_info *info, unsigned char *key, ...@@ -216,12 +216,12 @@ static void print_entry(struct bpf_map_info *info, unsigned char *key,
!break_names; !break_names;
printf("key:%c", break_names ? '\n' : ' '); printf("key:%c", break_names ? '\n' : ' ');
print_hex(key, info->key_size, " "); fprint_hex(stdout, key, info->key_size, " ");
printf(single_line ? " " : "\n"); printf(single_line ? " " : "\n");
printf("value:%c", break_names ? '\n' : ' '); printf("value:%c", break_names ? '\n' : ' ');
print_hex(value, info->value_size, " "); fprint_hex(stdout, value, info->value_size, " ");
printf("\n"); printf("\n");
} else { } else {
...@@ -230,13 +230,13 @@ static void print_entry(struct bpf_map_info *info, unsigned char *key, ...@@ -230,13 +230,13 @@ static void print_entry(struct bpf_map_info *info, unsigned char *key,
n = get_possible_cpus(); n = get_possible_cpus();
printf("key:\n"); printf("key:\n");
print_hex(key, info->key_size, " "); fprint_hex(stdout, key, info->key_size, " ");
printf("\n"); printf("\n");
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
printf("value (CPU %02d):%c", printf("value (CPU %02d):%c",
i, info->value_size > 16 ? '\n' : ' '); i, info->value_size > 16 ? '\n' : ' ');
print_hex(value + i * info->value_size, fprint_hex(stdout, value + i * info->value_size,
info->value_size, " "); info->value_size, " ");
printf("\n"); printf("\n");
} }
} }
...@@ -252,7 +252,7 @@ static char **parse_bytes(char **argv, const char *name, unsigned char *val, ...@@ -252,7 +252,7 @@ static char **parse_bytes(char **argv, const char *name, unsigned char *val,
val[i] = strtoul(argv[i], &endptr, 0); val[i] = strtoul(argv[i], &endptr, 0);
if (*endptr) { if (*endptr) {
err("error parsing byte: %s\n", argv[i]); err("error parsing byte: %s\n", argv[i]);
break; return NULL;
} }
i++; i++;
} }
...@@ -492,8 +492,8 @@ static int do_dump(int argc, char **argv) ...@@ -492,8 +492,8 @@ static int do_dump(int argc, char **argv)
print_entry(&info, key, value); print_entry(&info, key, value);
} else { } else {
info("can't lookup element with key: "); info("can't lookup element with key: ");
print_hex(key, info.key_size, " "); fprint_hex(stderr, key, info.key_size, " ");
printf("\n"); fprintf(stderr, "\n");
} }
prev_key = key; prev_key = key;
...@@ -587,7 +587,7 @@ static int do_lookup(int argc, char **argv) ...@@ -587,7 +587,7 @@ static int do_lookup(int argc, char **argv)
print_entry(&info, key, value); print_entry(&info, key, value);
} else if (errno == ENOENT) { } else if (errno == ENOENT) {
printf("key:\n"); printf("key:\n");
print_hex(key, info.key_size, " "); fprint_hex(stdout, key, info.key_size, " ");
printf("\n\nNot found\n"); printf("\n\nNot found\n");
} else { } else {
err("lookup failed: %s\n", strerror(errno)); err("lookup failed: %s\n", strerror(errno));
...@@ -642,14 +642,14 @@ static int do_getnext(int argc, char **argv) ...@@ -642,14 +642,14 @@ static int do_getnext(int argc, char **argv)
if (key) { if (key) {
printf("key:\n"); printf("key:\n");
print_hex(key, info.key_size, " "); fprint_hex(stdout, key, info.key_size, " ");
printf("\n"); printf("\n");
} else { } else {
printf("key: None\n"); printf("key: None\n");
} }
printf("next key:\n"); printf("next key:\n");
print_hex(nextkey, info.key_size, " "); fprint_hex(stdout, nextkey, info.key_size, " ");
printf("\n"); printf("\n");
exit_free: exit_free:
......
...@@ -224,7 +224,7 @@ static int show_prog(int fd) ...@@ -224,7 +224,7 @@ static int show_prog(int fd)
printf("name %s ", info.name); printf("name %s ", info.name);
printf("tag "); printf("tag ");
print_hex(info.tag, BPF_TAG_SIZE, ""); fprint_hex(stdout, info.tag, BPF_TAG_SIZE, "");
printf("\n"); printf("\n");
if (info.load_time) { if (info.load_time) {
...@@ -275,8 +275,10 @@ static int do_show(int argc, char **argv) ...@@ -275,8 +275,10 @@ static int do_show(int argc, char **argv)
while (true) { while (true) {
err = bpf_prog_get_next_id(id, &id); err = bpf_prog_get_next_id(id, &id);
if (err) { if (err) {
if (errno == ENOENT) if (errno == ENOENT) {
err = 0;
break; break;
}
err("can't get next program: %s\n", strerror(errno)); err("can't get next program: %s\n", strerror(errno));
if (errno == EINVAL) if (errno == EINVAL)
err("kernel too old?\n"); err("kernel too old?\n");
...@@ -311,20 +313,29 @@ static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) ...@@ -311,20 +313,29 @@ static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)
static void dump_xlated(void *buf, unsigned int len, bool opcodes) static void dump_xlated(void *buf, unsigned int len, bool opcodes)
{ {
struct bpf_insn *insn = buf; struct bpf_insn *insn = buf;
bool double_insn = false;
unsigned int i; unsigned int i;
for (i = 0; i < len / sizeof(*insn); i++) { for (i = 0; i < len / sizeof(*insn); i++) {
if (double_insn) {
double_insn = false;
continue;
}
double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
printf("% 4d: ", i); printf("% 4d: ", i);
print_bpf_insn(print_insn, NULL, insn + i, true); print_bpf_insn(print_insn, NULL, insn + i, true);
if (opcodes) { if (opcodes) {
printf(" "); printf(" ");
print_hex(insn + i, 8, " "); fprint_hex(stdout, insn + i, 8, " ");
if (double_insn && i < len - 1) {
printf(" ");
fprint_hex(stdout, insn + i + 1, 8, " ");
}
printf("\n"); printf("\n");
} }
if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW))
i++;
} }
} }
...@@ -414,7 +425,7 @@ static int do_dump(int argc, char **argv) ...@@ -414,7 +425,7 @@ static int do_dump(int argc, char **argv)
} }
if (*member_len > buf_size) { if (*member_len > buf_size) {
info("too many instructions returned\n"); err("too many instructions returned\n");
goto err_free; goto err_free;
} }
...@@ -458,8 +469,8 @@ static int do_help(int argc, char **argv) ...@@ -458,8 +469,8 @@ static int do_help(int argc, char **argv)
{ {
fprintf(stderr, fprintf(stderr,
"Usage: %s %s show [PROG]\n" "Usage: %s %s show [PROG]\n"
" %s %s dump xlated PROG [file FILE] [opcodes]\n" " %s %s dump xlated PROG [{ file FILE | opcodes }]\n"
" %s %s dump jited PROG [file FILE] [opcodes]\n" " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
" %s %s pin PROG FILE\n" " %s %s pin PROG FILE\n"
" %s %s help\n" " %s %s help\n"
"\n" "\n"
...@@ -473,6 +484,7 @@ static int do_help(int argc, char **argv) ...@@ -473,6 +484,7 @@ static int do_help(int argc, char **argv)
static const struct cmd cmds[] = { static const struct cmd cmds[] = {
{ "show", do_show }, { "show", do_show },
{ "help", do_help },
{ "dump", do_dump }, { "dump", do_dump },
{ "pin", do_pin }, { "pin", do_pin },
{ 0 } { 0 }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment