Merge branch 'bpftool-show-filenames-of-pinned-objects'
Prashant Bhole says: ==================== tools: bpftool: show filenames of pinned objects This patchset adds support to show pinned objects in object details. Patch1 adds a funtionality to open a path in bpf-fs regardless of its object type. Patch2 adds actual functionality by scanning the bpf-fs once and adding object information in hash table, with object id as a key. One object may be associated with multiple paths because an object can be pinned multiple times Patch3 adds command line option to enable this functionality. Making it optional because scanning bpf-fs can be costly. ==================== Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
commit
a8a6f1e4ea
@ -12,7 +12,7 @@ SYNOPSIS
|
|||||||
|
|
||||||
**bpftool** [*OPTIONS*] **map** *COMMAND*
|
**bpftool** [*OPTIONS*] **map** *COMMAND*
|
||||||
|
|
||||||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }
|
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
|
||||||
|
|
||||||
*COMMANDS* :=
|
*COMMANDS* :=
|
||||||
{ **show** | **dump** | **update** | **lookup** | **getnext** | **delete**
|
{ **show** | **dump** | **update** | **lookup** | **getnext** | **delete**
|
||||||
@ -86,6 +86,9 @@ OPTIONS
|
|||||||
-p, --pretty
|
-p, --pretty
|
||||||
Generate human-readable JSON output. Implies **-j**.
|
Generate human-readable JSON output. Implies **-j**.
|
||||||
|
|
||||||
|
-f, --bpffs
|
||||||
|
Show file names of pinned maps.
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
========
|
========
|
||||||
**# bpftool map show**
|
**# bpftool map show**
|
||||||
|
@ -12,7 +12,7 @@ SYNOPSIS
|
|||||||
|
|
||||||
**bpftool** [*OPTIONS*] **prog** *COMMAND*
|
**bpftool** [*OPTIONS*] **prog** *COMMAND*
|
||||||
|
|
||||||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }
|
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
|
||||||
|
|
||||||
*COMMANDS* :=
|
*COMMANDS* :=
|
||||||
{ **show** | **dump xlated** | **dump jited** | **pin** | **help** }
|
{ **show** | **dump xlated** | **dump jited** | **pin** | **help** }
|
||||||
@ -75,6 +75,9 @@ OPTIONS
|
|||||||
-p, --pretty
|
-p, --pretty
|
||||||
Generate human-readable JSON output. Implies **-j**.
|
Generate human-readable JSON output. Implies **-j**.
|
||||||
|
|
||||||
|
-f, --bpffs
|
||||||
|
Show file names of pinned programs.
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
========
|
========
|
||||||
**# bpftool prog show**
|
**# bpftool prog show**
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
/* Author: Jakub Kicinski <kubakici@wp.pl> */
|
/* Author: Jakub Kicinski <kubakici@wp.pl> */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fts.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <mntent.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -122,9 +124,8 @@ static int mnt_bpffs(const char *target, char *buff, size_t bufflen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
|
int open_obj_pinned(char *path)
|
||||||
{
|
{
|
||||||
enum bpf_obj_type type;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = bpf_obj_get(path);
|
fd = bpf_obj_get(path);
|
||||||
@ -136,6 +137,18 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
|
||||||
|
{
|
||||||
|
enum bpf_obj_type type;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open_obj_pinned(path);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
type = get_fd_type(fd);
|
type = get_fd_type(fd);
|
||||||
if (type < 0) {
|
if (type < 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
@ -310,3 +323,83 @@ void print_hex_data_json(uint8_t *data, size_t len)
|
|||||||
jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
|
jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
|
||||||
jsonw_end_array(json_wtr);
|
jsonw_end_array(json_wtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int build_pinned_obj_table(struct pinned_obj_table *tab,
|
||||||
|
enum bpf_obj_type type)
|
||||||
|
{
|
||||||
|
struct bpf_prog_info pinned_info = {};
|
||||||
|
struct pinned_obj *obj_node = NULL;
|
||||||
|
__u32 len = sizeof(pinned_info);
|
||||||
|
struct mntent *mntent = NULL;
|
||||||
|
enum bpf_obj_type objtype;
|
||||||
|
FILE *mntfile = NULL;
|
||||||
|
FTSENT *ftse = NULL;
|
||||||
|
FTS *fts = NULL;
|
||||||
|
int fd, err;
|
||||||
|
|
||||||
|
mntfile = setmntent("/proc/mounts", "r");
|
||||||
|
if (!mntfile)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((mntent = getmntent(mntfile))) {
|
||||||
|
char *path[] = { mntent->mnt_dir, NULL };
|
||||||
|
|
||||||
|
if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fts = fts_open(path, 0, NULL);
|
||||||
|
if (!fts)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
while ((ftse = fts_read(fts))) {
|
||||||
|
if (!(ftse->fts_info & FTS_F))
|
||||||
|
continue;
|
||||||
|
fd = open_obj_pinned(ftse->fts_path);
|
||||||
|
if (fd < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
objtype = get_fd_type(fd);
|
||||||
|
if (objtype != type) {
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memset(&pinned_info, 0, sizeof(pinned_info));
|
||||||
|
err = bpf_obj_get_info_by_fd(fd, &pinned_info, &len);
|
||||||
|
if (err) {
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_node = malloc(sizeof(*obj_node));
|
||||||
|
if (!obj_node) {
|
||||||
|
close(fd);
|
||||||
|
fts_close(fts);
|
||||||
|
fclose(mntfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(obj_node, 0, sizeof(*obj_node));
|
||||||
|
obj_node->id = pinned_info.id;
|
||||||
|
obj_node->path = strdup(ftse->fts_path);
|
||||||
|
hash_add(tab->table, &obj_node->hash, obj_node->id);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
fts_close(fts);
|
||||||
|
}
|
||||||
|
fclose(mntfile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_pinned_obj_table(struct pinned_obj_table *tab)
|
||||||
|
{
|
||||||
|
struct pinned_obj *obj;
|
||||||
|
struct hlist_node *tmp;
|
||||||
|
unsigned int bkt;
|
||||||
|
|
||||||
|
hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
|
||||||
|
hash_del(&obj->hash);
|
||||||
|
free(obj->path);
|
||||||
|
free(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -54,6 +54,9 @@ static int (*last_do_help)(int argc, char **argv);
|
|||||||
json_writer_t *json_wtr;
|
json_writer_t *json_wtr;
|
||||||
bool pretty_output;
|
bool pretty_output;
|
||||||
bool json_output;
|
bool json_output;
|
||||||
|
bool show_pinned;
|
||||||
|
struct pinned_obj_table prog_table;
|
||||||
|
struct pinned_obj_table map_table;
|
||||||
|
|
||||||
void usage(void)
|
void usage(void)
|
||||||
{
|
{
|
||||||
@ -263,6 +266,7 @@ int main(int argc, char **argv)
|
|||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "pretty", no_argument, NULL, 'p' },
|
{ "pretty", no_argument, NULL, 'p' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "bpffs", no_argument, NULL, 'f' },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
int opt, ret;
|
int opt, ret;
|
||||||
@ -270,9 +274,13 @@ int main(int argc, char **argv)
|
|||||||
last_do_help = do_help;
|
last_do_help = do_help;
|
||||||
pretty_output = false;
|
pretty_output = false;
|
||||||
json_output = false;
|
json_output = false;
|
||||||
|
show_pinned = false;
|
||||||
bin_name = argv[0];
|
bin_name = argv[0];
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "Vhpj",
|
hash_init(prog_table.table);
|
||||||
|
hash_init(map_table.table);
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "Vhpjf",
|
||||||
options, NULL)) >= 0) {
|
options, NULL)) >= 0) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'V':
|
case 'V':
|
||||||
@ -285,6 +293,9 @@ int main(int argc, char **argv)
|
|||||||
case 'j':
|
case 'j':
|
||||||
json_output = true;
|
json_output = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
show_pinned = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
@ -311,5 +322,10 @@ int main(int argc, char **argv)
|
|||||||
if (json_output)
|
if (json_output)
|
||||||
jsonw_destroy(&json_wtr);
|
jsonw_destroy(&json_wtr);
|
||||||
|
|
||||||
|
if (show_pinned) {
|
||||||
|
delete_pinned_obj_table(&prog_table);
|
||||||
|
delete_pinned_obj_table(&map_table);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/hashtable.h>
|
||||||
|
|
||||||
#include "json_writer.h"
|
#include "json_writer.h"
|
||||||
|
|
||||||
@ -58,7 +59,7 @@
|
|||||||
#define HELP_SPEC_PROGRAM \
|
#define HELP_SPEC_PROGRAM \
|
||||||
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
|
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
|
||||||
#define HELP_SPEC_OPTIONS \
|
#define HELP_SPEC_OPTIONS \
|
||||||
"OPTIONS := { {-j|--json} [{-p|--pretty}] }"
|
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }"
|
||||||
|
|
||||||
enum bpf_obj_type {
|
enum bpf_obj_type {
|
||||||
BPF_OBJ_UNKNOWN,
|
BPF_OBJ_UNKNOWN,
|
||||||
@ -70,6 +71,9 @@ extern const char *bin_name;
|
|||||||
|
|
||||||
extern json_writer_t *json_wtr;
|
extern json_writer_t *json_wtr;
|
||||||
extern bool json_output;
|
extern bool json_output;
|
||||||
|
extern bool show_pinned;
|
||||||
|
extern struct pinned_obj_table prog_table;
|
||||||
|
extern struct pinned_obj_table map_table;
|
||||||
|
|
||||||
void p_err(const char *fmt, ...);
|
void p_err(const char *fmt, ...);
|
||||||
void p_info(const char *fmt, ...);
|
void p_info(const char *fmt, ...);
|
||||||
@ -78,6 +82,20 @@ bool is_prefix(const char *pfx, const char *str);
|
|||||||
void fprint_hex(FILE *f, 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 pinned_obj_table {
|
||||||
|
DECLARE_HASHTABLE(table, 16);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pinned_obj {
|
||||||
|
__u32 id;
|
||||||
|
char *path;
|
||||||
|
struct hlist_node hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
int build_pinned_obj_table(struct pinned_obj_table *table,
|
||||||
|
enum bpf_obj_type type);
|
||||||
|
void delete_pinned_obj_table(struct pinned_obj_table *tab);
|
||||||
|
|
||||||
struct cmd {
|
struct cmd {
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
int (*func)(int argc, char **argv);
|
int (*func)(int argc, char **argv);
|
||||||
@ -89,6 +107,7 @@ int cmd_select(const struct cmd *cmds, int argc, char **argv,
|
|||||||
int get_fd_type(int fd);
|
int get_fd_type(int fd);
|
||||||
const char *get_fd_type_name(enum bpf_obj_type type);
|
const char *get_fd_type_name(enum bpf_obj_type type);
|
||||||
char *get_fdinfo(int fd, const char *key);
|
char *get_fdinfo(int fd, const char *key);
|
||||||
|
int open_obj_pinned(char *path);
|
||||||
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
|
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
|
||||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
|
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
|
||||||
|
|
||||||
|
@ -436,6 +436,18 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
|
|||||||
jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
|
jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
|
||||||
free(memlock);
|
free(memlock);
|
||||||
|
|
||||||
|
if (!hash_empty(map_table.table)) {
|
||||||
|
struct pinned_obj *obj;
|
||||||
|
|
||||||
|
jsonw_name(json_wtr, "pinned");
|
||||||
|
jsonw_start_array(json_wtr);
|
||||||
|
hash_for_each_possible(map_table.table, obj, hash, info->id) {
|
||||||
|
if (obj->id == info->id)
|
||||||
|
jsonw_string(json_wtr, obj->path);
|
||||||
|
}
|
||||||
|
jsonw_end_array(json_wtr);
|
||||||
|
}
|
||||||
|
|
||||||
jsonw_end_object(json_wtr);
|
jsonw_end_object(json_wtr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -466,7 +478,14 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
|||||||
free(memlock);
|
free(memlock);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
if (!hash_empty(map_table.table)) {
|
||||||
|
struct pinned_obj *obj;
|
||||||
|
|
||||||
|
hash_for_each_possible(map_table.table, obj, hash, info->id) {
|
||||||
|
if (obj->id == info->id)
|
||||||
|
printf("\tpinned %s\n", obj->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,6 +497,9 @@ static int do_show(int argc, char **argv)
|
|||||||
int err;
|
int err;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
if (show_pinned)
|
||||||
|
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
@ -272,6 +272,18 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
|
|||||||
if (info->nr_map_ids)
|
if (info->nr_map_ids)
|
||||||
show_prog_maps(fd, info->nr_map_ids);
|
show_prog_maps(fd, info->nr_map_ids);
|
||||||
|
|
||||||
|
if (!hash_empty(prog_table.table)) {
|
||||||
|
struct pinned_obj *obj;
|
||||||
|
|
||||||
|
jsonw_name(json_wtr, "pinned");
|
||||||
|
jsonw_start_array(json_wtr);
|
||||||
|
hash_for_each_possible(prog_table.table, obj, hash, info->id) {
|
||||||
|
if (obj->id == info->id)
|
||||||
|
jsonw_string(json_wtr, obj->path);
|
||||||
|
}
|
||||||
|
jsonw_end_array(json_wtr);
|
||||||
|
}
|
||||||
|
|
||||||
jsonw_end_object(json_wtr);
|
jsonw_end_object(json_wtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +343,16 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
|
|||||||
if (info->nr_map_ids)
|
if (info->nr_map_ids)
|
||||||
show_prog_maps(fd, info->nr_map_ids);
|
show_prog_maps(fd, info->nr_map_ids);
|
||||||
|
|
||||||
|
if (!hash_empty(prog_table.table)) {
|
||||||
|
struct pinned_obj *obj;
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
hash_for_each_possible(prog_table.table, obj, hash, info->id) {
|
||||||
|
if (obj->id == info->id)
|
||||||
|
printf("\tpinned %s\n", obj->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +382,9 @@ static int do_show(int argc, char **argv)
|
|||||||
int err;
|
int err;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
if (show_pinned)
|
||||||
|
build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
fd = prog_parse_fd(&argc, &argv);
|
fd = prog_parse_fd(&argc, &argv);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user