Commit ad8edd0d authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'link_query-bpf_iter'

Yonghong Song says:

====================
"link" has been an important concept for bpf ecosystem to connect
bpf program with other properties. Currently, the information related
information can be queried from userspace through bpf command
BPF_LINK_GET_NEXT_ID, BPF_LINK_GET_FD_BY_ID and BPF_OBJ_GET_INFO_BY_FD.
The information is also available by "cating" /proc/<pid>/fdinfo/<link_fd>.
Raw_tracepoint, tracing, cgroup, netns and xdp links are already
supported in the kernel and bpftool.

This patch added support for bpf iterator. Patch #1 added generic support
for link querying interface. Patch #2 implemented callback functions
for map element bpf iterators. Patch #3 added bpftool support.

Changelogs:
  v3 -> v4:
    . return target specific link_info even if target_name buffer
      is empty. (Andrii)
  v2 -> v3:
    . remove extra '\t' when fdinfo prints map_id to make parsing
      consistent. (Andrii)
  v1 -> v2:
    . fix checkpatch.pl warnings. (Jakub)
====================
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 149cb339 e60495ea
...@@ -1218,12 +1218,18 @@ typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog, ...@@ -1218,12 +1218,18 @@ typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,
union bpf_iter_link_info *linfo, union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux); struct bpf_iter_aux_info *aux);
typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux); typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *aux);
typedef void (*bpf_iter_show_fdinfo_t) (const struct bpf_iter_aux_info *aux,
struct seq_file *seq);
typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *aux,
struct bpf_link_info *info);
#define BPF_ITER_CTX_ARG_MAX 2 #define BPF_ITER_CTX_ARG_MAX 2
struct bpf_iter_reg { struct bpf_iter_reg {
const char *target; const char *target;
bpf_iter_attach_target_t attach_target; bpf_iter_attach_target_t attach_target;
bpf_iter_detach_target_t detach_target; bpf_iter_detach_target_t detach_target;
bpf_iter_show_fdinfo_t show_fdinfo;
bpf_iter_fill_link_info_t fill_link_info;
u32 ctx_arg_info_size; u32 ctx_arg_info_size;
struct bpf_ctx_arg_aux ctx_arg_info[BPF_ITER_CTX_ARG_MAX]; struct bpf_ctx_arg_aux ctx_arg_info[BPF_ITER_CTX_ARG_MAX];
const struct bpf_iter_seq_info *seq_info; const struct bpf_iter_seq_info *seq_info;
...@@ -1250,6 +1256,10 @@ int bpf_iter_new_fd(struct bpf_link *link); ...@@ -1250,6 +1256,10 @@ int bpf_iter_new_fd(struct bpf_link *link);
bool bpf_link_is_iter(struct bpf_link *link); bool bpf_link_is_iter(struct bpf_link *link);
struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop); struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop);
int bpf_iter_run_prog(struct bpf_prog *prog, void *ctx); int bpf_iter_run_prog(struct bpf_prog *prog, void *ctx);
void bpf_iter_map_show_fdinfo(const struct bpf_iter_aux_info *aux,
struct seq_file *seq);
int bpf_iter_map_fill_link_info(const struct bpf_iter_aux_info *aux,
struct bpf_link_info *info);
int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value); int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value);
int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value); int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value);
......
...@@ -4071,6 +4071,13 @@ struct bpf_link_info { ...@@ -4071,6 +4071,13 @@ struct bpf_link_info {
__u64 cgroup_id; __u64 cgroup_id;
__u32 attach_type; __u32 attach_type;
} cgroup; } cgroup;
struct {
__aligned_u64 target_name; /* in/out: target_name buffer ptr */
__u32 target_name_len; /* in/out: target_name buffer len */
union {
__u32 map_id;
} map;
} iter;
struct { struct {
__u32 netns_ino; __u32 netns_ino;
__u32 attach_type; __u32 attach_type;
......
...@@ -377,10 +377,68 @@ static int bpf_iter_link_replace(struct bpf_link *link, ...@@ -377,10 +377,68 @@ static int bpf_iter_link_replace(struct bpf_link *link,
return ret; return ret;
} }
static void bpf_iter_link_show_fdinfo(const struct bpf_link *link,
struct seq_file *seq)
{
struct bpf_iter_link *iter_link =
container_of(link, struct bpf_iter_link, link);
bpf_iter_show_fdinfo_t show_fdinfo;
seq_printf(seq,
"target_name:\t%s\n",
iter_link->tinfo->reg_info->target);
show_fdinfo = iter_link->tinfo->reg_info->show_fdinfo;
if (show_fdinfo)
show_fdinfo(&iter_link->aux, seq);
}
static int bpf_iter_link_fill_link_info(const struct bpf_link *link,
struct bpf_link_info *info)
{
struct bpf_iter_link *iter_link =
container_of(link, struct bpf_iter_link, link);
char __user *ubuf = u64_to_user_ptr(info->iter.target_name);
bpf_iter_fill_link_info_t fill_link_info;
u32 ulen = info->iter.target_name_len;
const char *target_name;
u32 target_len;
if (!ulen ^ !ubuf)
return -EINVAL;
target_name = iter_link->tinfo->reg_info->target;
target_len = strlen(target_name);
info->iter.target_name_len = target_len + 1;
if (ubuf) {
if (ulen >= target_len + 1) {
if (copy_to_user(ubuf, target_name, target_len + 1))
return -EFAULT;
} else {
char zero = '\0';
if (copy_to_user(ubuf, target_name, ulen - 1))
return -EFAULT;
if (put_user(zero, ubuf + ulen - 1))
return -EFAULT;
return -ENOSPC;
}
}
fill_link_info = iter_link->tinfo->reg_info->fill_link_info;
if (fill_link_info)
return fill_link_info(&iter_link->aux, info);
return 0;
}
static const struct bpf_link_ops bpf_iter_link_lops = { static const struct bpf_link_ops bpf_iter_link_lops = {
.release = bpf_iter_link_release, .release = bpf_iter_link_release,
.dealloc = bpf_iter_link_dealloc, .dealloc = bpf_iter_link_dealloc,
.update_prog = bpf_iter_link_replace, .update_prog = bpf_iter_link_replace,
.show_fdinfo = bpf_iter_link_show_fdinfo,
.fill_link_info = bpf_iter_link_fill_link_info,
}; };
bool bpf_link_is_iter(struct bpf_link *link) bool bpf_link_is_iter(struct bpf_link *link)
......
...@@ -149,6 +149,19 @@ static void bpf_iter_detach_map(struct bpf_iter_aux_info *aux) ...@@ -149,6 +149,19 @@ static void bpf_iter_detach_map(struct bpf_iter_aux_info *aux)
bpf_map_put_with_uref(aux->map); bpf_map_put_with_uref(aux->map);
} }
void bpf_iter_map_show_fdinfo(const struct bpf_iter_aux_info *aux,
struct seq_file *seq)
{
seq_printf(seq, "map_id:\t%u\n", aux->map->id);
}
int bpf_iter_map_fill_link_info(const struct bpf_iter_aux_info *aux,
struct bpf_link_info *info)
{
info->iter.map.map_id = aux->map->id;
return 0;
}
DEFINE_BPF_ITER_FUNC(bpf_map_elem, struct bpf_iter_meta *meta, DEFINE_BPF_ITER_FUNC(bpf_map_elem, struct bpf_iter_meta *meta,
struct bpf_map *map, void *key, void *value) struct bpf_map *map, void *key, void *value)
...@@ -156,6 +169,8 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = { ...@@ -156,6 +169,8 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {
.target = "bpf_map_elem", .target = "bpf_map_elem",
.attach_target = bpf_iter_attach_map, .attach_target = bpf_iter_attach_map,
.detach_target = bpf_iter_detach_map, .detach_target = bpf_iter_detach_map,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
.ctx_arg_info_size = 2, .ctx_arg_info_size = 2,
.ctx_arg_info = { .ctx_arg_info = {
{ offsetof(struct bpf_iter__bpf_map_elem, key), { offsetof(struct bpf_iter__bpf_map_elem, key),
......
...@@ -1437,6 +1437,8 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = { ...@@ -1437,6 +1437,8 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
.target = "bpf_sk_storage_map", .target = "bpf_sk_storage_map",
.attach_target = bpf_iter_attach_map, .attach_target = bpf_iter_attach_map,
.detach_target = bpf_iter_detach_map, .detach_target = bpf_iter_detach_map,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
.ctx_arg_info_size = 2, .ctx_arg_info_size = 2,
.ctx_arg_info = { .ctx_arg_info = {
{ offsetof(struct bpf_iter__bpf_sk_storage_map, sk), { offsetof(struct bpf_iter__bpf_sk_storage_map, sk),
......
...@@ -77,6 +77,22 @@ static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr) ...@@ -77,6 +77,22 @@ static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
jsonw_uint_field(wtr, "attach_type", attach_type); jsonw_uint_field(wtr, "attach_type", attach_type);
} }
static bool is_iter_map_target(const char *target_name)
{
return strcmp(target_name, "bpf_map_elem") == 0 ||
strcmp(target_name, "bpf_sk_storage_map") == 0;
}
static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
{
const char *target_name = u64_to_ptr(info->iter.target_name);
jsonw_string_field(wtr, "target_name", target_name);
if (is_iter_map_target(target_name))
jsonw_uint_field(wtr, "map_id", info->iter.map.map_id);
}
static int get_prog_info(int prog_id, struct bpf_prog_info *info) static int get_prog_info(int prog_id, struct bpf_prog_info *info)
{ {
__u32 len = sizeof(*info); __u32 len = sizeof(*info);
...@@ -128,6 +144,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) ...@@ -128,6 +144,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
info->cgroup.cgroup_id); info->cgroup.cgroup_id);
show_link_attach_type_json(info->cgroup.attach_type, json_wtr); show_link_attach_type_json(info->cgroup.attach_type, json_wtr);
break; break;
case BPF_LINK_TYPE_ITER:
show_iter_json(info, json_wtr);
break;
case BPF_LINK_TYPE_NETNS: case BPF_LINK_TYPE_NETNS:
jsonw_uint_field(json_wtr, "netns_ino", jsonw_uint_field(json_wtr, "netns_ino",
info->netns.netns_ino); info->netns.netns_ino);
...@@ -175,6 +194,16 @@ static void show_link_attach_type_plain(__u32 attach_type) ...@@ -175,6 +194,16 @@ static void show_link_attach_type_plain(__u32 attach_type)
printf("attach_type %u ", attach_type); printf("attach_type %u ", attach_type);
} }
static void show_iter_plain(struct bpf_link_info *info)
{
const char *target_name = u64_to_ptr(info->iter.target_name);
printf("target_name %s ", target_name);
if (is_iter_map_target(target_name))
printf("map_id %u ", info->iter.map.map_id);
}
static int show_link_close_plain(int fd, struct bpf_link_info *info) static int show_link_close_plain(int fd, struct bpf_link_info *info)
{ {
struct bpf_prog_info prog_info; struct bpf_prog_info prog_info;
...@@ -204,6 +233,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) ...@@ -204,6 +233,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id);
show_link_attach_type_plain(info->cgroup.attach_type); show_link_attach_type_plain(info->cgroup.attach_type);
break; break;
case BPF_LINK_TYPE_ITER:
show_iter_plain(info);
break;
case BPF_LINK_TYPE_NETNS: case BPF_LINK_TYPE_NETNS:
printf("\n\tnetns_ino %u ", info->netns.netns_ino); printf("\n\tnetns_ino %u ", info->netns.netns_ino);
show_link_attach_type_plain(info->netns.attach_type); show_link_attach_type_plain(info->netns.attach_type);
...@@ -231,7 +263,7 @@ static int do_show_link(int fd) ...@@ -231,7 +263,7 @@ static int do_show_link(int fd)
{ {
struct bpf_link_info info; struct bpf_link_info info;
__u32 len = sizeof(info); __u32 len = sizeof(info);
char raw_tp_name[256]; char buf[256];
int err; int err;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
...@@ -245,8 +277,14 @@ static int do_show_link(int fd) ...@@ -245,8 +277,14 @@ static int do_show_link(int fd)
} }
if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT && if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT &&
!info.raw_tracepoint.tp_name) { !info.raw_tracepoint.tp_name) {
info.raw_tracepoint.tp_name = (unsigned long)&raw_tp_name; info.raw_tracepoint.tp_name = (unsigned long)&buf;
info.raw_tracepoint.tp_name_len = sizeof(raw_tp_name); info.raw_tracepoint.tp_name_len = sizeof(buf);
goto again;
}
if (info.type == BPF_LINK_TYPE_ITER &&
!info.iter.target_name) {
info.iter.target_name = (unsigned long)&buf;
info.iter.target_name_len = sizeof(buf);
goto again; goto again;
} }
......
...@@ -4071,6 +4071,13 @@ struct bpf_link_info { ...@@ -4071,6 +4071,13 @@ struct bpf_link_info {
__u64 cgroup_id; __u64 cgroup_id;
__u32 attach_type; __u32 attach_type;
} cgroup; } cgroup;
struct {
__aligned_u64 target_name; /* in/out: target_name buffer ptr */
__u32 target_name_len; /* in/out: target_name buffer len */
union {
__u32 map_id;
} map;
} iter;
struct { struct {
__u32 netns_ino; __u32 netns_ino;
__u32 attach_type; __u32 attach_type;
......
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