Message ID | 20200428054944.4015462-5-andriin@fb.com |
---|---|
State | Changes Requested |
Delegated to: | BPF Maintainers |
Headers | show |
Series | bpf_link observability APIs | expand |
Andrii Nakryiko <andriin@fb.com> writes: > Add ability to fetch bpf_link details through BPF_OBJ_GET_INFO_BY_FD command. > Also enhance show_fdinfo to potentially include bpf_link type-specific > information (similarly to obj_info). > > Also introduce enum bpf_link_type stored in bpf_link itself and expose it in > UAPI. bpf_link_tracing also now will store and return bpf_attach_type. > > Signed-off-by: Andrii Nakryiko <andriin@fb.com> > --- > include/linux/bpf-cgroup.h | 2 - > include/linux/bpf.h | 10 +- > include/linux/bpf_types.h | 6 ++ > include/uapi/linux/bpf.h | 28 ++++++ > kernel/bpf/btf.c | 2 + > kernel/bpf/cgroup.c | 45 ++++++++- > kernel/bpf/syscall.c | 164 +++++++++++++++++++++++++++++---- > kernel/bpf/verifier.c | 2 + > tools/include/uapi/linux/bpf.h | 31 +++++++ > 9 files changed, 266 insertions(+), 24 deletions(-) > > diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h > index d2d969669564..ab95824a1d99 100644 > --- a/include/linux/bpf-cgroup.h > +++ b/include/linux/bpf-cgroup.h > @@ -57,8 +57,6 @@ struct bpf_cgroup_link { > enum bpf_attach_type type; > }; > > -extern const struct bpf_link_ops bpf_cgroup_link_lops; > - > struct bpf_prog_list { > struct list_head node; > struct bpf_prog *prog; > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 875d1f0af803..701c4387c711 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1026,9 +1026,11 @@ extern const struct file_operations bpf_prog_fops; > extern const struct bpf_verifier_ops _name ## _verifier_ops; > #define BPF_MAP_TYPE(_id, _ops) \ > extern const struct bpf_map_ops _ops; > +#define BPF_LINK_TYPE(_id, _name) > #include <linux/bpf_types.h> > #undef BPF_PROG_TYPE > #undef BPF_MAP_TYPE > +#undef BPF_LINK_TYPE > > extern const struct bpf_prog_ops bpf_offload_prog_ops; > extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops; > @@ -1086,6 +1088,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog); > struct bpf_link { > atomic64_t refcnt; > u32 id; > + enum bpf_link_type type; > const struct bpf_link_ops *ops; > struct bpf_prog *prog; > struct work_struct work; > @@ -1103,9 +1106,14 @@ struct bpf_link_ops { > void (*dealloc)(struct bpf_link *link); > int (*update_prog)(struct bpf_link *link, struct bpf_prog *new_prog, > struct bpf_prog *old_prog); > + void (*show_fdinfo)(const struct bpf_link *link, struct seq_file *seq); > + int (*fill_link_info)(const struct bpf_link *link, > + struct bpf_link_info *info, > + const struct bpf_link_info *uinfo, > + u32 info_len); > }; > > -void bpf_link_init(struct bpf_link *link, > +void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, > const struct bpf_link_ops *ops, struct bpf_prog *prog); > int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer); > int bpf_link_settle(struct bpf_link_primer *primer); > diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h > index ba0c2d56f8a3..8345cdf553b8 100644 > --- a/include/linux/bpf_types.h > +++ b/include/linux/bpf_types.h > @@ -118,3 +118,9 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops) > #if defined(CONFIG_BPF_JIT) > BPF_MAP_TYPE(BPF_MAP_TYPE_STRUCT_OPS, bpf_struct_ops_map_ops) > #endif > + > +BPF_LINK_TYPE(BPF_LINK_TYPE_RAW_TRACEPOINT, raw_tracepoint) > +BPF_LINK_TYPE(BPF_LINK_TYPE_TRACING, tracing) > +#ifdef CONFIG_CGROUP_BPF > +BPF_LINK_TYPE(BPF_LINK_TYPE_CGROUP, cgroup) > +#endif > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 7e6541fceade..0eccafae55bb 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -222,6 +222,15 @@ enum bpf_attach_type { > > #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE > > +enum bpf_link_type { > + BPF_LINK_TYPE_UNSPEC = 0, > + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, > + BPF_LINK_TYPE_TRACING = 2, > + BPF_LINK_TYPE_CGROUP = 3, > + > + MAX_BPF_LINK_TYPE, > +}; > + > /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command > * > * NONE(default): No further bpf programs allowed in the subtree. > @@ -3612,6 +3621,25 @@ struct bpf_btf_info { > __u32 id; > } __attribute__((aligned(8))); > > +struct bpf_link_info { > + __u32 type; > + __u32 id; > + __u32 prog_id; > + union { > + struct { > + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ > + __u32 tp_name_len; /* in/out: tp_name buffer len */ > + } raw_tracepoint; > + struct { > + __u32 attach_type; > + } tracing; On the RFC I asked whether we could get the attach target here as well. You said you'd look into it; what happened to that? :) -Toke
On Tue, Apr 28, 2020 at 2:46 AM Toke Høiland-Jørgensen <toke@redhat.com> wrote: > > Andrii Nakryiko <andriin@fb.com> writes: > > > Add ability to fetch bpf_link details through BPF_OBJ_GET_INFO_BY_FD command. > > Also enhance show_fdinfo to potentially include bpf_link type-specific > > information (similarly to obj_info). > > > > Also introduce enum bpf_link_type stored in bpf_link itself and expose it in > > UAPI. bpf_link_tracing also now will store and return bpf_attach_type. > > > > Signed-off-by: Andrii Nakryiko <andriin@fb.com> > > --- > > include/linux/bpf-cgroup.h | 2 - > > include/linux/bpf.h | 10 +- > > include/linux/bpf_types.h | 6 ++ > > include/uapi/linux/bpf.h | 28 ++++++ > > kernel/bpf/btf.c | 2 + > > kernel/bpf/cgroup.c | 45 ++++++++- > > kernel/bpf/syscall.c | 164 +++++++++++++++++++++++++++++---- > > kernel/bpf/verifier.c | 2 + > > tools/include/uapi/linux/bpf.h | 31 +++++++ > > 9 files changed, 266 insertions(+), 24 deletions(-) > > > > diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h > > index d2d969669564..ab95824a1d99 100644 > > --- a/include/linux/bpf-cgroup.h > > +++ b/include/linux/bpf-cgroup.h > > @@ -57,8 +57,6 @@ struct bpf_cgroup_link { > > enum bpf_attach_type type; > > }; > > > > -extern const struct bpf_link_ops bpf_cgroup_link_lops; > > - > > struct bpf_prog_list { > > struct list_head node; > > struct bpf_prog *prog; > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > index 875d1f0af803..701c4387c711 100644 > > --- a/include/linux/bpf.h > > +++ b/include/linux/bpf.h > > @@ -1026,9 +1026,11 @@ extern const struct file_operations bpf_prog_fops; > > extern const struct bpf_verifier_ops _name ## _verifier_ops; > > #define BPF_MAP_TYPE(_id, _ops) \ > > extern const struct bpf_map_ops _ops; > > +#define BPF_LINK_TYPE(_id, _name) > > #include <linux/bpf_types.h> > > #undef BPF_PROG_TYPE > > #undef BPF_MAP_TYPE > > +#undef BPF_LINK_TYPE > > > > extern const struct bpf_prog_ops bpf_offload_prog_ops; > > extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops; > > @@ -1086,6 +1088,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog); > > struct bpf_link { > > atomic64_t refcnt; > > u32 id; > > + enum bpf_link_type type; > > const struct bpf_link_ops *ops; > > struct bpf_prog *prog; > > struct work_struct work; > > @@ -1103,9 +1106,14 @@ struct bpf_link_ops { > > void (*dealloc)(struct bpf_link *link); > > int (*update_prog)(struct bpf_link *link, struct bpf_prog *new_prog, > > struct bpf_prog *old_prog); > > + void (*show_fdinfo)(const struct bpf_link *link, struct seq_file *seq); > > + int (*fill_link_info)(const struct bpf_link *link, > > + struct bpf_link_info *info, > > + const struct bpf_link_info *uinfo, > > + u32 info_len); > > }; > > > > -void bpf_link_init(struct bpf_link *link, > > +void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, > > const struct bpf_link_ops *ops, struct bpf_prog *prog); > > int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer); > > int bpf_link_settle(struct bpf_link_primer *primer); > > diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h > > index ba0c2d56f8a3..8345cdf553b8 100644 > > --- a/include/linux/bpf_types.h > > +++ b/include/linux/bpf_types.h > > @@ -118,3 +118,9 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops) > > #if defined(CONFIG_BPF_JIT) > > BPF_MAP_TYPE(BPF_MAP_TYPE_STRUCT_OPS, bpf_struct_ops_map_ops) > > #endif > > + > > +BPF_LINK_TYPE(BPF_LINK_TYPE_RAW_TRACEPOINT, raw_tracepoint) > > +BPF_LINK_TYPE(BPF_LINK_TYPE_TRACING, tracing) > > +#ifdef CONFIG_CGROUP_BPF > > +BPF_LINK_TYPE(BPF_LINK_TYPE_CGROUP, cgroup) > > +#endif > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > > index 7e6541fceade..0eccafae55bb 100644 > > --- a/include/uapi/linux/bpf.h > > +++ b/include/uapi/linux/bpf.h > > @@ -222,6 +222,15 @@ enum bpf_attach_type { > > > > #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE > > > > +enum bpf_link_type { > > + BPF_LINK_TYPE_UNSPEC = 0, > > + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, > > + BPF_LINK_TYPE_TRACING = 2, > > + BPF_LINK_TYPE_CGROUP = 3, > > + > > + MAX_BPF_LINK_TYPE, > > +}; > > + > > /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command > > * > > * NONE(default): No further bpf programs allowed in the subtree. > > @@ -3612,6 +3621,25 @@ struct bpf_btf_info { > > __u32 id; > > } __attribute__((aligned(8))); > > > > +struct bpf_link_info { > > + __u32 type; > > + __u32 id; > > + __u32 prog_id; > > + union { > > + struct { > > + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ > > + __u32 tp_name_len; /* in/out: tp_name buffer len */ > > + } raw_tracepoint; > > + struct { > > + __u32 attach_type; > > + } tracing; > > On the RFC I asked whether we could get the attach target here as well. > You said you'd look into it; what happened to that? :) > Right, sorry, forgot to mention this. I did take a look, but tracing links are quite diverse, so I didn't see one clear way to structure such "target" information, so I'd say we should push it into a separate patch/discussion. E.g., fentry/fexit/fmod_exit are attached to kernel functions (how do we represent that), freplace are attached to another BPF program (this is a bit clearer how to represent, but how do we combine that with fentry/fexit info?). LSM is also attached to kernel function, but who knows, maybe we want slightly more extended semantics for it. Either way, I don't see one best way to structure this information and would want to avoid blocking on this for this series. Also bpf_link_info is extensible, so it's not a problem to extend it in follow up patches. Does it make sense? > -Toke >
Andrii Nakryiko <andrii.nakryiko@gmail.com> writes: > On Tue, Apr 28, 2020 at 2:46 AM Toke Høiland-Jørgensen <toke@redhat.com> wrote: >> >> Andrii Nakryiko <andriin@fb.com> writes: >> >> > Add ability to fetch bpf_link details through BPF_OBJ_GET_INFO_BY_FD command. >> > Also enhance show_fdinfo to potentially include bpf_link type-specific >> > information (similarly to obj_info). >> > >> > Also introduce enum bpf_link_type stored in bpf_link itself and expose it in >> > UAPI. bpf_link_tracing also now will store and return bpf_attach_type. >> > >> > Signed-off-by: Andrii Nakryiko <andriin@fb.com> >> > --- >> > include/linux/bpf-cgroup.h | 2 - >> > include/linux/bpf.h | 10 +- >> > include/linux/bpf_types.h | 6 ++ >> > include/uapi/linux/bpf.h | 28 ++++++ >> > kernel/bpf/btf.c | 2 + >> > kernel/bpf/cgroup.c | 45 ++++++++- >> > kernel/bpf/syscall.c | 164 +++++++++++++++++++++++++++++---- >> > kernel/bpf/verifier.c | 2 + >> > tools/include/uapi/linux/bpf.h | 31 +++++++ >> > 9 files changed, 266 insertions(+), 24 deletions(-) >> > >> > diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h >> > index d2d969669564..ab95824a1d99 100644 >> > --- a/include/linux/bpf-cgroup.h >> > +++ b/include/linux/bpf-cgroup.h >> > @@ -57,8 +57,6 @@ struct bpf_cgroup_link { >> > enum bpf_attach_type type; >> > }; >> > >> > -extern const struct bpf_link_ops bpf_cgroup_link_lops; >> > - >> > struct bpf_prog_list { >> > struct list_head node; >> > struct bpf_prog *prog; >> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h >> > index 875d1f0af803..701c4387c711 100644 >> > --- a/include/linux/bpf.h >> > +++ b/include/linux/bpf.h >> > @@ -1026,9 +1026,11 @@ extern const struct file_operations bpf_prog_fops; >> > extern const struct bpf_verifier_ops _name ## _verifier_ops; >> > #define BPF_MAP_TYPE(_id, _ops) \ >> > extern const struct bpf_map_ops _ops; >> > +#define BPF_LINK_TYPE(_id, _name) >> > #include <linux/bpf_types.h> >> > #undef BPF_PROG_TYPE >> > #undef BPF_MAP_TYPE >> > +#undef BPF_LINK_TYPE >> > >> > extern const struct bpf_prog_ops bpf_offload_prog_ops; >> > extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops; >> > @@ -1086,6 +1088,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog); >> > struct bpf_link { >> > atomic64_t refcnt; >> > u32 id; >> > + enum bpf_link_type type; >> > const struct bpf_link_ops *ops; >> > struct bpf_prog *prog; >> > struct work_struct work; >> > @@ -1103,9 +1106,14 @@ struct bpf_link_ops { >> > void (*dealloc)(struct bpf_link *link); >> > int (*update_prog)(struct bpf_link *link, struct bpf_prog *new_prog, >> > struct bpf_prog *old_prog); >> > + void (*show_fdinfo)(const struct bpf_link *link, struct seq_file *seq); >> > + int (*fill_link_info)(const struct bpf_link *link, >> > + struct bpf_link_info *info, >> > + const struct bpf_link_info *uinfo, >> > + u32 info_len); >> > }; >> > >> > -void bpf_link_init(struct bpf_link *link, >> > +void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, >> > const struct bpf_link_ops *ops, struct bpf_prog *prog); >> > int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer); >> > int bpf_link_settle(struct bpf_link_primer *primer); >> > diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h >> > index ba0c2d56f8a3..8345cdf553b8 100644 >> > --- a/include/linux/bpf_types.h >> > +++ b/include/linux/bpf_types.h >> > @@ -118,3 +118,9 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops) >> > #if defined(CONFIG_BPF_JIT) >> > BPF_MAP_TYPE(BPF_MAP_TYPE_STRUCT_OPS, bpf_struct_ops_map_ops) >> > #endif >> > + >> > +BPF_LINK_TYPE(BPF_LINK_TYPE_RAW_TRACEPOINT, raw_tracepoint) >> > +BPF_LINK_TYPE(BPF_LINK_TYPE_TRACING, tracing) >> > +#ifdef CONFIG_CGROUP_BPF >> > +BPF_LINK_TYPE(BPF_LINK_TYPE_CGROUP, cgroup) >> > +#endif >> > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h >> > index 7e6541fceade..0eccafae55bb 100644 >> > --- a/include/uapi/linux/bpf.h >> > +++ b/include/uapi/linux/bpf.h >> > @@ -222,6 +222,15 @@ enum bpf_attach_type { >> > >> > #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE >> > >> > +enum bpf_link_type { >> > + BPF_LINK_TYPE_UNSPEC = 0, >> > + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, >> > + BPF_LINK_TYPE_TRACING = 2, >> > + BPF_LINK_TYPE_CGROUP = 3, >> > + >> > + MAX_BPF_LINK_TYPE, >> > +}; >> > + >> > /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command >> > * >> > * NONE(default): No further bpf programs allowed in the subtree. >> > @@ -3612,6 +3621,25 @@ struct bpf_btf_info { >> > __u32 id; >> > } __attribute__((aligned(8))); >> > >> > +struct bpf_link_info { >> > + __u32 type; >> > + __u32 id; >> > + __u32 prog_id; >> > + union { >> > + struct { >> > + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ >> > + __u32 tp_name_len; /* in/out: tp_name buffer len */ >> > + } raw_tracepoint; >> > + struct { >> > + __u32 attach_type; >> > + } tracing; >> >> On the RFC I asked whether we could get the attach target here as well. >> You said you'd look into it; what happened to that? :) >> > > Right, sorry, forgot to mention this. I did take a look, but tracing > links are quite diverse, so I didn't see one clear way to structure > such "target" information, so I'd say we should push it into a > separate patch/discussion. E.g., fentry/fexit/fmod_exit are attached > to kernel functions (how do we represent that), freplace are attached > to another BPF program (this is a bit clearer how to represent, but > how do we combine that with fentry/fexit info?). LSM is also attached > to kernel function, but who knows, maybe we want slightly more > extended semantics for it. Either way, I don't see one best way to > structure this information and would want to avoid blocking on this > for this series. Also bpf_link_info is extensible, so it's not a > problem to extend it in follow up patches. > > Does it make sense? Yup, fair enough, I can live with deferring this to a later series :) -Toke
Hi Andrii, I love your patch! Yet something to improve: [auto build test ERROR on bpf-next/master] [also build test ERROR on bpf/master cgroup/for-next net/master net-next/master v5.7-rc3 next-20200428] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/Andrii-Nakryiko/bpf_link-observability-APIs/20200428-215720 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: sh-randconfig-a001-20200428 (attached as .config) compiler: sh4-linux-gcc (GCC) 9.3.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day GCC_VERSION=9.3.0 make.cross ARCH=sh If you fix the issue, kindly add following tag as appropriate Reported-by: kbuild test robot <lkp@intel.com> All errors (new ones prefixed by >>): sh4-linux-ld: kernel/bpf/syscall.o: in function `bpf_raw_tp_link_fill_link_info': >> kernel/bpf/syscall.c:2570: undefined reference to `__get_user_unknown' vim +2570 kernel/bpf/syscall.c 2547 2548 static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link, 2549 struct bpf_link_info *info, 2550 const struct bpf_link_info *uinfo, 2551 u32 info_len) 2552 { 2553 struct bpf_raw_tp_link *raw_tp_link = 2554 container_of(link, struct bpf_raw_tp_link, link); 2555 u64 ubuf_ptr; 2556 char __user *ubuf = u64_to_user_ptr(uinfo->raw_tracepoint.tp_name); 2557 const char *tp_name = raw_tp_link->btp->tp->name; 2558 size_t tp_len; 2559 u32 ulen; 2560 2561 if (get_user(ulen, &uinfo->raw_tracepoint.tp_name_len)) 2562 return -EFAULT; 2563 if (get_user(ubuf_ptr, &uinfo->raw_tracepoint.tp_name)) 2564 return -EFAULT; 2565 ubuf = u64_to_user_ptr(ubuf_ptr); 2566 2567 if (ulen && !ubuf) 2568 return -EINVAL; 2569 if (!ubuf) > 2570 return 0; 2571 2572 tp_len = strlen(raw_tp_link->btp->tp->name); 2573 info->raw_tracepoint.tp_name_len = tp_len + 1; 2574 info->raw_tracepoint.tp_name = (u64)(unsigned long)ubuf; 2575 2576 if (ulen >= tp_len + 1) { 2577 if (copy_to_user(ubuf, tp_name, tp_len + 1)) 2578 return -EFAULT; 2579 } else { 2580 char zero = '\0'; 2581 2582 if (copy_to_user(ubuf, tp_name, ulen - 1)) 2583 return -EFAULT; 2584 if (put_user(zero, ubuf + ulen - 1)) 2585 return -EFAULT; 2586 return -ENOSPC; 2587 } 2588 2589 return 0; 2590 } 2591 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index d2d969669564..ab95824a1d99 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -57,8 +57,6 @@ struct bpf_cgroup_link { enum bpf_attach_type type; }; -extern const struct bpf_link_ops bpf_cgroup_link_lops; - struct bpf_prog_list { struct list_head node; struct bpf_prog *prog; diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 875d1f0af803..701c4387c711 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1026,9 +1026,11 @@ extern const struct file_operations bpf_prog_fops; extern const struct bpf_verifier_ops _name ## _verifier_ops; #define BPF_MAP_TYPE(_id, _ops) \ extern const struct bpf_map_ops _ops; +#define BPF_LINK_TYPE(_id, _name) #include <linux/bpf_types.h> #undef BPF_PROG_TYPE #undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE extern const struct bpf_prog_ops bpf_offload_prog_ops; extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops; @@ -1086,6 +1088,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog); struct bpf_link { atomic64_t refcnt; u32 id; + enum bpf_link_type type; const struct bpf_link_ops *ops; struct bpf_prog *prog; struct work_struct work; @@ -1103,9 +1106,14 @@ struct bpf_link_ops { void (*dealloc)(struct bpf_link *link); int (*update_prog)(struct bpf_link *link, struct bpf_prog *new_prog, struct bpf_prog *old_prog); + void (*show_fdinfo)(const struct bpf_link *link, struct seq_file *seq); + int (*fill_link_info)(const struct bpf_link *link, + struct bpf_link_info *info, + const struct bpf_link_info *uinfo, + u32 info_len); }; -void bpf_link_init(struct bpf_link *link, +void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, const struct bpf_link_ops *ops, struct bpf_prog *prog); int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer); int bpf_link_settle(struct bpf_link_primer *primer); diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index ba0c2d56f8a3..8345cdf553b8 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -118,3 +118,9 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_STACK, stack_map_ops) #if defined(CONFIG_BPF_JIT) BPF_MAP_TYPE(BPF_MAP_TYPE_STRUCT_OPS, bpf_struct_ops_map_ops) #endif + +BPF_LINK_TYPE(BPF_LINK_TYPE_RAW_TRACEPOINT, raw_tracepoint) +BPF_LINK_TYPE(BPF_LINK_TYPE_TRACING, tracing) +#ifdef CONFIG_CGROUP_BPF +BPF_LINK_TYPE(BPF_LINK_TYPE_CGROUP, cgroup) +#endif diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 7e6541fceade..0eccafae55bb 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -222,6 +222,15 @@ enum bpf_attach_type { #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE +enum bpf_link_type { + BPF_LINK_TYPE_UNSPEC = 0, + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, + BPF_LINK_TYPE_TRACING = 2, + BPF_LINK_TYPE_CGROUP = 3, + + MAX_BPF_LINK_TYPE, +}; + /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command * * NONE(default): No further bpf programs allowed in the subtree. @@ -3612,6 +3621,25 @@ struct bpf_btf_info { __u32 id; } __attribute__((aligned(8))); +struct bpf_link_info { + __u32 type; + __u32 id; + __u32 prog_id; + union { + struct { + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ + __u32 tp_name_len; /* in/out: tp_name buffer len */ + } raw_tracepoint; + struct { + __u32 attach_type; + } tracing; + struct { + __u64 cgroup_id; + __u32 attach_type; + } cgroup; + }; +} __attribute__((aligned(8))); + /* User bpf_sock_addr struct to access socket fields and sockaddr struct passed * by user and intended to be used by socket (e.g. to bind to, depends on * attach attach type). diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index d65c6912bdaf..a2cfba89a8e1 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3482,6 +3482,7 @@ extern char __weak __stop_BTF[]; extern struct btf *btf_vmlinux; #define BPF_MAP_TYPE(_id, _ops) +#define BPF_LINK_TYPE(_id, _name) static union { struct bpf_ctx_convert { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ @@ -3508,6 +3509,7 @@ static u8 bpf_ctx_convert_map[] = { 0, /* avoid empty array */ }; #undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE static const struct btf_member * btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf, diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index beb8307b16c6..316a3c436ccd 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -833,10 +833,50 @@ static void bpf_cgroup_link_dealloc(struct bpf_link *link) kfree(cg_link); } -const struct bpf_link_ops bpf_cgroup_link_lops = { +static void bpf_cgroup_link_show_fdinfo(const struct bpf_link *link, + struct seq_file *seq) +{ + struct bpf_cgroup_link *cg_link = + container_of(link, struct bpf_cgroup_link, link); + u64 cg_id = 0; + + mutex_lock(&cgroup_mutex); + if (cg_link->cgroup) + cg_id = cgroup_id(cg_link->cgroup); + mutex_unlock(&cgroup_mutex); + + seq_printf(seq, + "cgroup_id:\t%llu\n" + "attach_type:\t%d\n", + cg_id, + cg_link->type); +} + +static int bpf_cgroup_link_fill_link_info(const struct bpf_link *link, + struct bpf_link_info *info, + const struct bpf_link_info *uinfo, + u32 info_len) +{ + struct bpf_cgroup_link *cg_link = + container_of(link, struct bpf_cgroup_link, link); + u64 cg_id = 0; + + mutex_lock(&cgroup_mutex); + if (cg_link->cgroup) + cg_id = cgroup_id(cg_link->cgroup); + mutex_unlock(&cgroup_mutex); + + info->cgroup.cgroup_id = cg_id; + info->cgroup.attach_type = cg_link->type; + return 0; +} + +static const struct bpf_link_ops bpf_cgroup_link_lops = { .release = bpf_cgroup_link_release, .dealloc = bpf_cgroup_link_dealloc, .update_prog = cgroup_bpf_replace, + .show_fdinfo = bpf_cgroup_link_show_fdinfo, + .fill_link_info = bpf_cgroup_link_fill_link_info, }; int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) @@ -858,7 +898,8 @@ int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) err = -ENOMEM; goto out_put_cgroup; } - bpf_link_init(&link->link, &bpf_cgroup_link_lops, prog); + bpf_link_init(&link->link, BPF_LINK_TYPE_CGROUP, &bpf_cgroup_link_lops, + prog); link->cgroup = cgrp; link->type = attr->link_create.attach_type; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f296c15b8b3e..0c113a05aadb 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -51,9 +51,11 @@ static const struct bpf_map_ops * const bpf_map_types[] = { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) #define BPF_MAP_TYPE(_id, _ops) \ [_id] = &_ops, +#define BPF_LINK_TYPE(_id, _name) #include <linux/bpf_types.h> #undef BPF_PROG_TYPE #undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE }; /* @@ -1548,9 +1550,11 @@ static const struct bpf_prog_ops * const bpf_prog_types[] = { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ [_id] = & _name ## _prog_ops, #define BPF_MAP_TYPE(_id, _ops) +#define BPF_LINK_TYPE(_id, _name) #include <linux/bpf_types.h> #undef BPF_PROG_TYPE #undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE }; static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) @@ -2183,10 +2187,11 @@ static int bpf_obj_get(const union bpf_attr *attr) attr->file_flags); } -void bpf_link_init(struct bpf_link *link, +void bpf_link_init(struct bpf_link *link, enum bpf_link_type type, const struct bpf_link_ops *ops, struct bpf_prog *prog) { atomic64_set(&link->refcnt, 1); + link->type = type; link->id = 0; link->ops = ops; link->prog = prog; @@ -2268,27 +2273,23 @@ static int bpf_link_release(struct inode *inode, struct file *filp) return 0; } -#ifdef CONFIG_PROC_FS -static const struct bpf_link_ops bpf_raw_tp_lops; -static const struct bpf_link_ops bpf_tracing_link_lops; +#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) +#define BPF_MAP_TYPE(_id, _ops) +#define BPF_LINK_TYPE(_id, _name) [_id] = #_name, +static const char *bpf_link_type_strs[] = { + [BPF_LINK_TYPE_UNSPEC] = "<invalid>", +#include <linux/bpf_types.h> +}; +#undef BPF_PROG_TYPE +#undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE +#ifdef CONFIG_PROC_FS static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) { const struct bpf_link *link = filp->private_data; const struct bpf_prog *prog = link->prog; char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; - const char *link_type; - - if (link->ops == &bpf_raw_tp_lops) - link_type = "raw_tracepoint"; - else if (link->ops == &bpf_tracing_link_lops) - link_type = "tracing"; -#ifdef CONFIG_CGROUP_BPF - else if (link->ops == &bpf_cgroup_link_lops) - link_type = "cgroup"; -#endif - else - link_type = "unknown"; bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); seq_printf(m, @@ -2296,10 +2297,12 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) "link_id:\t%u\n" "prog_tag:\t%s\n" "prog_id:\t%u\n", - link_type, + bpf_link_type_strs[link->type], link->id, prog_tag, prog->aux->id); + if (link->ops->show_fdinfo) + link->ops->show_fdinfo(link, m); } #endif @@ -2403,6 +2406,7 @@ struct bpf_link *bpf_link_get_from_fd(u32 ufd) struct bpf_tracing_link { struct bpf_link link; + enum bpf_attach_type attach_type; }; static void bpf_tracing_link_release(struct bpf_link *link) @@ -2418,9 +2422,35 @@ static void bpf_tracing_link_dealloc(struct bpf_link *link) kfree(tr_link); } +static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link, + struct seq_file *seq) +{ + struct bpf_tracing_link *tr_link = + container_of(link, struct bpf_tracing_link, link); + + seq_printf(seq, + "attach_type:\t%d\n", + tr_link->attach_type); +} + +static int bpf_tracing_link_fill_link_info(const struct bpf_link *link, + struct bpf_link_info *info, + const struct bpf_link_info *uinfo, + u32 info_len) +{ + struct bpf_tracing_link *tr_link = + container_of(link, struct bpf_tracing_link, link); + + info->tracing.attach_type = tr_link->attach_type; + + return 0; +} + static const struct bpf_link_ops bpf_tracing_link_lops = { .release = bpf_tracing_link_release, .dealloc = bpf_tracing_link_dealloc, + .show_fdinfo = bpf_tracing_link_show_fdinfo, + .fill_link_info = bpf_tracing_link_fill_link_info, }; static int bpf_tracing_prog_attach(struct bpf_prog *prog) @@ -2460,7 +2490,9 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog) err = -ENOMEM; goto out_put_prog; } - bpf_link_init(&link->link, &bpf_tracing_link_lops, prog); + bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING, + &bpf_tracing_link_lops, prog); + link->attach_type = prog->expected_attach_type; err = bpf_link_prime(&link->link, &link_primer); if (err) { @@ -2502,9 +2534,66 @@ static void bpf_raw_tp_link_dealloc(struct bpf_link *link) kfree(raw_tp); } +static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link, + struct seq_file *seq) +{ + struct bpf_raw_tp_link *raw_tp_link = + container_of(link, struct bpf_raw_tp_link, link); + + seq_printf(seq, + "tp_name:\t%s\n", + raw_tp_link->btp->tp->name); +} + +static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link, + struct bpf_link_info *info, + const struct bpf_link_info *uinfo, + u32 info_len) +{ + struct bpf_raw_tp_link *raw_tp_link = + container_of(link, struct bpf_raw_tp_link, link); + u64 ubuf_ptr; + char __user *ubuf = u64_to_user_ptr(uinfo->raw_tracepoint.tp_name); + const char *tp_name = raw_tp_link->btp->tp->name; + size_t tp_len; + u32 ulen; + + if (get_user(ulen, &uinfo->raw_tracepoint.tp_name_len)) + return -EFAULT; + if (get_user(ubuf_ptr, &uinfo->raw_tracepoint.tp_name)) + return -EFAULT; + ubuf = u64_to_user_ptr(ubuf_ptr); + + if (ulen && !ubuf) + return -EINVAL; + if (!ubuf) + return 0; + + tp_len = strlen(raw_tp_link->btp->tp->name); + info->raw_tracepoint.tp_name_len = tp_len + 1; + info->raw_tracepoint.tp_name = (u64)(unsigned long)ubuf; + + if (ulen >= tp_len + 1) { + if (copy_to_user(ubuf, tp_name, tp_len + 1)) + return -EFAULT; + } else { + char zero = '\0'; + + if (copy_to_user(ubuf, tp_name, ulen - 1)) + return -EFAULT; + if (put_user(zero, ubuf + ulen - 1)) + return -EFAULT; + return -ENOSPC; + } + + return 0; +} + static const struct bpf_link_ops bpf_raw_tp_link_lops = { .release = bpf_raw_tp_link_release, .dealloc = bpf_raw_tp_link_dealloc, + .show_fdinfo = bpf_raw_tp_link_show_fdinfo, + .fill_link_info = bpf_raw_tp_link_fill_link_info, }; #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd @@ -2570,7 +2659,8 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) err = -ENOMEM; goto out_put_btp; } - bpf_link_init(&link->link, &bpf_raw_tp_link_lops, prog); + bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT, + &bpf_raw_tp_link_lops, prog); link->btp = btp; err = bpf_link_prime(&link->link, &link_primer); @@ -3366,6 +3456,39 @@ static int bpf_btf_get_info_by_fd(struct btf *btf, return btf_get_info_by_fd(btf, attr, uattr); } +static int bpf_link_get_info_by_fd(struct bpf_link *link, + const union bpf_attr *attr, + union bpf_attr __user *uattr) +{ + struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info); + struct bpf_link_info info; + u32 info_len = attr->info.info_len; + int err; + + err = bpf_check_uarg_tail_zero(uinfo, sizeof(info), info_len); + if (err) + return err; + info_len = min_t(u32, sizeof(info), info_len); + + memset(&info, 0, sizeof(info)); + info.type = link->type; + info.id = link->id; + info.prog_id = link->prog->aux->id; + + if (link->ops->fill_link_info) { + err = link->ops->fill_link_info(link, &info, uinfo, info_len); + if (err) + return err; + } + + if (copy_to_user(uinfo, &info, info_len) || + put_user(info_len, &uattr->info.info_len)) + return -EFAULT; + + return 0; +} + + #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, @@ -3390,6 +3513,9 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, uattr); else if (f.file->f_op == &btf_fops) err = bpf_btf_get_info_by_fd(f.file->private_data, attr, uattr); + else if (f.file->f_op == &bpf_link_fops) + err = bpf_link_get_info_by_fd(f.file->private_data, + attr, uattr); else err = -EINVAL; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 91728e0f27eb..2b337e32aa94 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -28,9 +28,11 @@ static const struct bpf_verifier_ops * const bpf_verifier_ops[] = { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \ [_id] = & _name ## _verifier_ops, #define BPF_MAP_TYPE(_id, _ops) +#define BPF_LINK_TYPE(_id, _name) #include <linux/bpf_types.h> #undef BPF_PROG_TYPE #undef BPF_MAP_TYPE +#undef BPF_LINK_TYPE }; /* bpf_check() is a static code analyzer that walks eBPF program diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4a6c47f3febe..0eccafae55bb 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -113,6 +113,8 @@ enum bpf_cmd { BPF_MAP_DELETE_BATCH, BPF_LINK_CREATE, BPF_LINK_UPDATE, + BPF_LINK_GET_FD_BY_ID, + BPF_LINK_GET_NEXT_ID, }; enum bpf_map_type { @@ -220,6 +222,15 @@ enum bpf_attach_type { #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE +enum bpf_link_type { + BPF_LINK_TYPE_UNSPEC = 0, + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, + BPF_LINK_TYPE_TRACING = 2, + BPF_LINK_TYPE_CGROUP = 3, + + MAX_BPF_LINK_TYPE, +}; + /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command * * NONE(default): No further bpf programs allowed in the subtree. @@ -523,6 +534,7 @@ union bpf_attr { __u32 prog_id; __u32 map_id; __u32 btf_id; + __u32 link_id; }; __u32 next_id; __u32 open_flags; @@ -3609,6 +3621,25 @@ struct bpf_btf_info { __u32 id; } __attribute__((aligned(8))); +struct bpf_link_info { + __u32 type; + __u32 id; + __u32 prog_id; + union { + struct { + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ + __u32 tp_name_len; /* in/out: tp_name buffer len */ + } raw_tracepoint; + struct { + __u32 attach_type; + } tracing; + struct { + __u64 cgroup_id; + __u32 attach_type; + } cgroup; + }; +} __attribute__((aligned(8))); + /* User bpf_sock_addr struct to access socket fields and sockaddr struct passed * by user and intended to be used by socket (e.g. to bind to, depends on * attach attach type).
Add ability to fetch bpf_link details through BPF_OBJ_GET_INFO_BY_FD command. Also enhance show_fdinfo to potentially include bpf_link type-specific information (similarly to obj_info). Also introduce enum bpf_link_type stored in bpf_link itself and expose it in UAPI. bpf_link_tracing also now will store and return bpf_attach_type. Signed-off-by: Andrii Nakryiko <andriin@fb.com> --- include/linux/bpf-cgroup.h | 2 - include/linux/bpf.h | 10 +- include/linux/bpf_types.h | 6 ++ include/uapi/linux/bpf.h | 28 ++++++ kernel/bpf/btf.c | 2 + kernel/bpf/cgroup.c | 45 ++++++++- kernel/bpf/syscall.c | 164 +++++++++++++++++++++++++++++---- kernel/bpf/verifier.c | 2 + tools/include/uapi/linux/bpf.h | 31 +++++++ 9 files changed, 266 insertions(+), 24 deletions(-)