diff mbox series

[net-next,V3,2/3] tools: bpftool: show filenames of pinned objects

Message ID 20171106060632.3380-3-bhole_prashant_q7@lab.ntt.co.jp
State Superseded, archived
Delegated to: David Miller
Headers show
Series tools: bpftool: show filenames of pinned objects | expand

Commit Message

Prashant Bhole Nov. 6, 2017, 6:06 a.m. UTC
Added support to show filenames of pinned objects.

For example:

root@test# ./bpftool prog
3: tracepoint  name tracepoint__irq  tag f677a7dd722299a3
    loaded_at Oct 26/11:39  uid 0
    xlated 160B  not jited  memlock 4096B  map_ids 4
    pinned /sys/fs/bpf/softirq_prog

4: tracepoint  name tracepoint__irq  tag ea5dc530d00b92b6
    loaded_at Oct 26/11:39  uid 0
    xlated 392B  not jited  memlock 4096B  map_ids 4,6

root@test# ./bpftool --json --pretty prog
[{
        "id": 3,
        "type": "tracepoint",
        "name": "tracepoint__irq",
        "tag": "f677a7dd722299a3",
        "loaded_at": "Oct 26/11:39",
        "uid": 0,
        "bytes_xlated": 160,
        "jited": false,
        "bytes_memlock": 4096,
        "map_ids": [4
        ],
        "pinned": ["/sys/fs/bpf/softirq_prog"
        ]
    },{
        "id": 4,
        "type": "tracepoint",
        "name": "tracepoint__irq",
        "tag": "ea5dc530d00b92b6",
        "loaded_at": "Oct 26/11:39",
        "uid": 0,
        "bytes_xlated": 392,
        "jited": false,
        "bytes_memlock": 4096,
        "map_ids": [4,6
        ],
        "pinned": []
    }
]

root@test# ./bpftool map
4: hash  name start  flags 0x0
    key 4B  value 16B  max_entries 10240  memlock 1003520B
    pinned /sys/fs/bpf/softirq_map1
5: hash  name iptr  flags 0x0
    key 4B  value 8B  max_entries 10240  memlock 921600B

root@test# ./bpftool --json --pretty map
[{
        "id": 4,
        "type": "hash",
        "name": "start",
        "flags": 0,
        "bytes_key": 4,
        "bytes_value": 16,
        "max_entries": 10240,
        "bytes_memlock": 1003520,
        "pinned": ["/sys/fs/bpf/softirq_map1"
        ]
    },{
        "id": 5,
        "type": "hash",
        "name": "iptr",
        "flags": 0,
        "bytes_key": 4,
        "bytes_value": 8,
        "max_entries": 10240,
        "bytes_memlock": 921600,
        "pinned": []
    }
]

Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
---
v2:
 - Dynamically identify bpf-fs moutpoint
 - Close files descriptors before returning on error
 - Fixed line break for proper output formatting
 - Code style: wrapped lines > 80, used reverse christmastree style

v3:
 - Handle multiple bpffs mountpoints
 - Code style: fixed line break indentation

 tools/bpf/bpftool/common.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/bpf/bpftool/main.c   |  8 +++++
 tools/bpf/bpftool/main.h   | 17 ++++++++++
 tools/bpf/bpftool/map.c    | 21 ++++++++++++
 tools/bpf/bpftool/prog.c   | 24 +++++++++++++
 5 files changed, 155 insertions(+)

Comments

Jakub Kicinski Nov. 7, 2017, 12:36 p.m. UTC | #1
On Mon,  6 Nov 2017 15:06:31 +0900, Prashant Bhole wrote:
> Added support to show filenames of pinned objects.
> ...
> Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>

Thanks for the changes, a couple more nit picks, sorry for not spotting
them earlier.

> v2:
>  - Dynamically identify bpf-fs moutpoint
>  - Close files descriptors before returning on error
>  - Fixed line break for proper output formatting
>  - Code style: wrapped lines > 80, used reverse christmastree style
> 
> v3:
>  - Handle multiple bpffs mountpoints
>  - Code style: fixed line break indentation
> 
>  tools/bpf/bpftool/common.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++
>  tools/bpf/bpftool/main.c   |  8 +++++
>  tools/bpf/bpftool/main.h   | 17 ++++++++++
>  tools/bpf/bpftool/map.c    | 21 ++++++++++++
>  tools/bpf/bpftool/prog.c   | 24 +++++++++++++
>  5 files changed, 155 insertions(+)
> 
> diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
> index 4556947709ee..152c5bdbe2e9 100644
> --- a/tools/bpf/bpftool/common.c
> +++ b/tools/bpf/bpftool/common.c
> @@ -45,6 +45,8 @@
>  #include <sys/mount.h>
>  #include <sys/types.h>
>  #include <sys/vfs.h>
> +#include <mntent.h>
> +#include <fts.h>

Please try to keep includes in an alphabetical order.

>  #include <bpf.h>
>  
> @@ -290,3 +292,86 @@ void print_hex_data_json(uint8_t *data, size_t len)
>  		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
>  	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 = {};
> +	__u32 len = sizeof(pinned_info);
> +	struct pinned_obj *obj_node = NULL;
> +	enum bpf_obj_type objtype;
> +	struct mntent *mntent = NULL;

Please try to order variable declarations longest to shortest.

> +	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)) != NULL) {

Please try to avoid comparisons to NULL, writing:

	if (ptr)

is more intuitive to most C programmers than:

	if (ptr != NULL)

> +		char *path[] = {mntent->mnt_dir, 0};

Shouldn't there be spaces after and before the curly braces?  Does
checkpatch --strict not warn about this?

> +
> +		if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
> +			continue;
> +
> +		fts = fts_open(path, 0, NULL);
> +		if (!fts)
> +			continue;
> +
> +		while ((ftse = fts_read(fts)) != NULL) {
> +			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;
> +
> +	if (hash_empty(tab->table))
> +		return;

is this necessary?  Does hash_for_each_safe() not work with empty table?

> +	hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
> +		hash_del(&obj->hash);
> +		free(obj->path);
> +		free(obj);
> +	}
> +}
Prashant Bhole Nov. 8, 2017, 2:34 a.m. UTC | #2
> -----Original Message-----
> From: Jakub Kicinski [mailto:jakub.kicinski@netronome.com]
> 
> On Mon,  6 Nov 2017 15:06:31 +0900, Prashant Bhole wrote:
> > Added support to show filenames of pinned objects.
> > ...
> > Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
> 
> Thanks for the changes, a couple more nit picks, sorry for not spotting
them
> earlier.
> 
> > v2:
> >  - Dynamically identify bpf-fs moutpoint
> >  - Close files descriptors before returning on error
> >  - Fixed line break for proper output formatting
> >  - Code style: wrapped lines > 80, used reverse christmastree style
> >
> > v3:
> >  - Handle multiple bpffs mountpoints
> >  - Code style: fixed line break indentation
> >
> >  tools/bpf/bpftool/common.c | 85
> ++++++++++++++++++++++++++++++++++++++++++++++
> >  tools/bpf/bpftool/main.c   |  8 +++++
> >  tools/bpf/bpftool/main.h   | 17 ++++++++++
> >  tools/bpf/bpftool/map.c    | 21 ++++++++++++
> >  tools/bpf/bpftool/prog.c   | 24 +++++++++++++
> >  5 files changed, 155 insertions(+)
> >
> > diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
> > index 4556947709ee..152c5bdbe2e9 100644
> > --- a/tools/bpf/bpftool/common.c
> > +++ b/tools/bpf/bpftool/common.c
> > @@ -45,6 +45,8 @@
> >  #include <sys/mount.h>
> >  #include <sys/types.h>
> >  #include <sys/vfs.h>
> > +#include <mntent.h>
> > +#include <fts.h>
> 
> Please try to keep includes in an alphabetical order.
> 
> >  #include <bpf.h>
> >
> > @@ -290,3 +292,86 @@ void print_hex_data_json(uint8_t *data, size_t len)
> >  		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
> >  	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 = {};
> > +	__u32 len = sizeof(pinned_info);
> > +	struct pinned_obj *obj_node = NULL;
> > +	enum bpf_obj_type objtype;
> > +	struct mntent *mntent = NULL;
> 
> Please try to order variable declarations longest to shortest.
> 
> > +	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)) != NULL) {
> 
> Please try to avoid comparisons to NULL, writing:
> 
> 	if (ptr)
> 
> is more intuitive to most C programmers than:
> 
> 	if (ptr != NULL)

Jakub,
Thank you for comments. I agree with using 'if (ptr)' for simple check, but
here it is an assignment.
It doesn't look intuitive and looks like a typo if I change it to:
         while ((mntent = getmntent(mntfile))) {

> 
> > +		char *path[] = {mntent->mnt_dir, 0};
> 
> Shouldn't there be spaces after and before the curly braces?  Does
checkpatch --
> strict not warn about this?

I will add spaces. checkpatch complained about this not being static const,
but doing so causes compiler warning because it doesn't match with signature
of fts_open()

I will submit v4 with changes for other comments if you are ok with replies
above.

Prashant
Jakub Kicinski Nov. 8, 2017, 4:33 a.m. UTC | #3
On Wed, 8 Nov 2017 11:34:44 +0900, Prashant Bhole wrote:
> > > +	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)) != NULL) {  
> > 
> > Please try to avoid comparisons to NULL, writing:
> > 
> > 	if (ptr)
> > 
> > is more intuitive to most C programmers than:
> > 
> > 	if (ptr != NULL)  
> 
> Jakub,
> Thank you for comments. I agree with using 'if (ptr)' for simple check, but
> here it is an assignment.
> It doesn't look intuitive and looks like a typo if I change it to:
>          while ((mntent = getmntent(mntfile))) {

I still prefer this, if you don't mind.

> >   
> > > +		char *path[] = {mntent->mnt_dir, 0};  
> > 
> > Shouldn't there be spaces after and before the curly braces?  Does  
> checkpatch --
> > strict not warn about this?  
> 
> I will add spaces. checkpatch complained about this not being static const,
> but doing so causes compiler warning because it doesn't match with signature
> of fts_open()

Right, that's OK to ignore.  Could you also make the 0 into a NULL,
though?

> I will submit v4 with changes for other comments if you are ok with replies
> above.

Thank you!
diff mbox series

Patch

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 4556947709ee..152c5bdbe2e9 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -45,6 +45,8 @@ 
 #include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
+#include <mntent.h>
+#include <fts.h>
 
 #include <bpf.h>
 
@@ -290,3 +292,86 @@  void print_hex_data_json(uint8_t *data, size_t len)
 		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
 	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 = {};
+	__u32 len = sizeof(pinned_info);
+	struct pinned_obj *obj_node = NULL;
+	enum bpf_obj_type objtype;
+	struct mntent *mntent = NULL;
+	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)) != NULL) {
+		char *path[] = {mntent->mnt_dir, 0};
+
+		if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
+			continue;
+
+		fts = fts_open(path, 0, NULL);
+		if (!fts)
+			continue;
+
+		while ((ftse = fts_read(fts)) != NULL) {
+			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;
+
+	if (hash_empty(tab->table))
+		return;
+
+	hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
+		hash_del(&obj->hash);
+		free(obj->path);
+		free(obj);
+	}
+}
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index 78d9afb74ef4..6ad53f1797fa 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -54,6 +54,8 @@  static int (*last_do_help)(int argc, char **argv);
 json_writer_t *json_wtr;
 bool pretty_output;
 bool json_output;
+struct pinned_obj_table prog_table;
+struct pinned_obj_table map_table;
 
 void usage(void)
 {
@@ -272,6 +274,9 @@  int main(int argc, char **argv)
 	json_output = false;
 	bin_name = argv[0];
 
+	hash_init(prog_table.table);
+	hash_init(map_table.table);
+
 	while ((opt = getopt_long(argc, argv, "Vhpj",
 				  options, NULL)) >= 0) {
 		switch (opt) {
@@ -311,5 +316,8 @@  int main(int argc, char **argv)
 	if (json_output)
 		jsonw_destroy(&json_wtr);
 
+	delete_pinned_obj_table(&prog_table);
+	delete_pinned_obj_table(&map_table);
+
 	return ret;
 }
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 4b5685005cb0..726f6e27a706 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -42,6 +42,7 @@ 
 #include <stdio.h>
 #include <linux/bpf.h>
 #include <linux/kernel.h>
+#include <linux/hashtable.h>
 
 #include "json_writer.h"
 
@@ -70,11 +71,27 @@  extern const char *bin_name;
 
 extern json_writer_t *json_wtr;
 extern bool json_output;
+extern struct pinned_obj_table prog_table;
+extern struct pinned_obj_table map_table;
 
 bool is_prefix(const char *pfx, const char *str);
 void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
 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 {
 	const char *cmd;
 	int (*func)(int argc, char **argv);
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index e978ab23a77f..de0980657cef 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -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));
 	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);
 
 	return 0;
@@ -466,7 +478,14 @@  static int show_map_close_plain(int fd, struct bpf_map_info *info)
 	free(memlock);
 
 	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;
 }
 
@@ -478,6 +497,8 @@  static int do_show(int argc, char **argv)
 	int err;
 	int fd;
 
+	build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
+
 	if (argc == 2) {
 		fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
 		if (fd < 0)
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 250f80fd46aa..11375f669fc0 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -256,6 +256,18 @@  static void print_prog_json(struct bpf_prog_info *info, int fd)
 	if (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);
 }
 
@@ -300,6 +312,16 @@  static void print_prog_plain(struct bpf_prog_info *info, int fd)
 	if (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");
 }
 
@@ -329,6 +351,8 @@  static int do_show(int argc, char **argv)
 	int err;
 	int fd;
 
+	build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
+
 	if (argc == 2) {
 		fd = prog_parse_fd(&argc, &argv);
 		if (fd < 0)