Преглед изворни кода

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: David S. Miller <davem@davemloft.net>
David S. Miller пре 8 година
родитељ
комит
a8e8c0ecb4

+ 4 - 4
tools/bpf/bpftool/Documentation/bpftool-prog.rst

@@ -11,8 +11,8 @@ SYNOPSIS
 ========
 ========
 
 
 |	**bpftool** prog show [*PROG*]
 |	**bpftool** prog show [*PROG*]
-|	**bpftool** prog dump xlated *PROG* [file *FILE*] [opcodes]
-|	**bpftool** prog dump jited  *PROG* [file *FILE*] [opcodes]
+|	**bpftool** prog dump xlated *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
 		  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.

+ 2 - 0
tools/bpf/bpftool/Documentation/bpftool.rst

@@ -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* :=

+ 17 - 5
tools/bpf/bpftool/main.c

@@ -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)
 	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)
 	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)
 		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[] = {
 	{ "batch",	do_batch },
 	{ "batch",	do_batch },
 	{ "prog",	do_prog },
 	{ "prog",	do_prog },
 	{ "map",	do_map },
 	{ "map",	do_map },
+	{ "version",	do_version },
 	{ 0 }
 	{ 0 }
 };
 };
 
 

+ 1 - 1
tools/bpf/bpftool/main.h

@@ -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 {

+ 11 - 11
tools/bpf/bpftool/map.c

@@ -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,
 		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,
-				  info->value_size, " ");
+			fprint_hex(stdout, value + i * 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,
 		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)
 			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, " ");
-			printf("\n");
+			fprint_hex(stderr, key, info.key_size, " ");
+			fprintf(stderr, "\n");
 		}
 		}
 
 
 		prev_key = key;
 		prev_key = key;
@@ -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)
 
 
 	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:

+ 21 - 9
tools/bpf/bpftool/prog.c

@@ -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)
 	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, ...)
 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)
 	}
 	}
 
 
 	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)
 {
 {
 	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 jited  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 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)
 
 
 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 }