Commit 2c76238e authored by Quentin Monnet's avatar Quentin Monnet Committed by Daniel Borkmann
Browse files

bpftool: Add "bootstrap" feature to version output



Along with the version number, "bpftool version" displays a list of
features that were selected at compilation time for bpftool. It would be
useful to indicate in that list whether a binary is a bootstrap version
of bpftool. Given that an increasing number of components rely on
bootstrap versions for generating skeletons, this could help understand
what a binary is capable of if it has been copied outside of the usual
"bootstrap" directory.

To detect a bootstrap version, we simply rely on the absence of
implementation for the do_prog() function. To do this, we must move the
(unchanged) list of commands before do_version(), which in turn requires
renaming this "cmds" array to avoid shadowing it with the "cmds"
argument in cmd_select().

Signed-off-by: default avatarQuentin Monnet <quentin@isovalent.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20221020100332.69563-1-quentin@isovalent.com
parent 7e5eb725
Loading
Loading
Loading
Loading
+49 −32
Original line number Diff line number Diff line
@@ -71,6 +71,27 @@ static int do_help(int argc, char **argv)
	return 0;
}

static int do_batch(int argc, char **argv);
static int do_version(int argc, char **argv);

static const struct cmd commands[] = {
	{ "help",	do_help },
	{ "batch",	do_batch },
	{ "prog",	do_prog },
	{ "map",	do_map },
	{ "link",	do_link },
	{ "cgroup",	do_cgroup },
	{ "perf",	do_perf },
	{ "net",	do_net },
	{ "feature",	do_feature },
	{ "btf",	do_btf },
	{ "gen",	do_gen },
	{ "struct_ops",	do_struct_ops },
	{ "iter",	do_iter },
	{ "version",	do_version },
	{ 0 }
};

#ifndef BPFTOOL_VERSION
/* bpftool's major and minor version numbers are aligned on libbpf's. There is
 * an offset of 6 for the version number, because bpftool's version was higher
@@ -82,6 +103,15 @@ static int do_help(int argc, char **argv)
#define BPFTOOL_PATCH_VERSION 0
#endif

static void
print_feature(const char *feature, bool state, unsigned int *nb_features)
{
	if (state) {
		printf("%s %s", *nb_features ? "," : "", feature);
		*nb_features = *nb_features + 1;
	}
}

static int do_version(int argc, char **argv)
{
#ifdef HAVE_LIBBFD_SUPPORT
@@ -94,6 +124,18 @@ static int do_version(int argc, char **argv)
#else
	const bool has_skeletons = true;
#endif
	bool bootstrap = false;
	int i;

	for (i = 0; commands[i].cmd; i++) {
		if (!strcmp(commands[i].cmd, "prog")) {
			/* Assume we run a bootstrap version if "bpftool prog"
			 * is not available.
			 */
			bootstrap = !commands[i].func;
			break;
		}
	}

	if (json_output) {
		jsonw_start_object(json_wtr);	/* root object */
@@ -114,6 +156,7 @@ static int do_version(int argc, char **argv)
		jsonw_bool_field(json_wtr, "libbfd", has_libbfd);
		jsonw_bool_field(json_wtr, "libbpf_strict", !legacy_libbpf);
		jsonw_bool_field(json_wtr, "skeletons", has_skeletons);
		jsonw_bool_field(json_wtr, "bootstrap", bootstrap);
		jsonw_end_object(json_wtr);	/* features */

		jsonw_end_object(json_wtr);	/* root object */
@@ -128,16 +171,10 @@ static int do_version(int argc, char **argv)
#endif
		printf("using libbpf %s\n", libbpf_version_string());
		printf("features:");
		if (has_libbfd) {
			printf(" libbfd");
			nb_features++;
		}
		if (!legacy_libbpf) {
			printf("%s libbpf_strict", nb_features++ ? "," : "");
			nb_features++;
		}
		if (has_skeletons)
			printf("%s skeletons", nb_features++ ? "," : "");
		print_feature("libbfd", has_libbfd, &nb_features);
		print_feature("libbpf_strict", !legacy_libbpf, &nb_features);
		print_feature("skeletons", has_skeletons, &nb_features);
		print_feature("bootstrap", bootstrap, &nb_features);
		printf("\n");
	}
	return 0;
@@ -279,26 +316,6 @@ static int make_args(char *line, char *n_argv[], int maxargs, int cmd_nb)
	return n_argc;
}

static int do_batch(int argc, char **argv);

static const struct cmd cmds[] = {
	{ "help",	do_help },
	{ "batch",	do_batch },
	{ "prog",	do_prog },
	{ "map",	do_map },
	{ "link",	do_link },
	{ "cgroup",	do_cgroup },
	{ "perf",	do_perf },
	{ "net",	do_net },
	{ "feature",	do_feature },
	{ "btf",	do_btf },
	{ "gen",	do_gen },
	{ "struct_ops",	do_struct_ops },
	{ "iter",	do_iter },
	{ "version",	do_version },
	{ 0 }
};

static int do_batch(int argc, char **argv)
{
	char buf[BATCH_LINE_LEN_MAX], contline[BATCH_LINE_LEN_MAX];
@@ -386,7 +403,7 @@ static int do_batch(int argc, char **argv)
			jsonw_name(json_wtr, "output");
		}

		err = cmd_select(cmds, n_argc, n_argv, do_help);
		err = cmd_select(commands, n_argc, n_argv, do_help);

		if (json_output)
			jsonw_end_object(json_wtr);
@@ -528,7 +545,7 @@ int main(int argc, char **argv)
	if (version_requested)
		return do_version(argc, argv);

	ret = cmd_select(cmds, argc, argv, do_help);
	ret = cmd_select(commands, argc, argv, do_help);

	if (json_output)
		jsonw_destroy(&json_wtr);