1*9f883612SDmitrii Dolgov // SPDX-License-Identifier: GPL-2.0-only
2*9f883612SDmitrii Dolgov /* Copyright (c) 2022 Red Hat, Inc. */
3*9f883612SDmitrii Dolgov #include <linux/bpf.h>
4*9f883612SDmitrii Dolgov #include <linux/fs.h>
5*9f883612SDmitrii Dolgov #include <linux/filter.h>
6*9f883612SDmitrii Dolgov #include <linux/kernel.h>
7*9f883612SDmitrii Dolgov #include <linux/btf_ids.h>
8*9f883612SDmitrii Dolgov
9*9f883612SDmitrii Dolgov struct bpf_iter_seq_link_info {
10*9f883612SDmitrii Dolgov u32 link_id;
11*9f883612SDmitrii Dolgov };
12*9f883612SDmitrii Dolgov
bpf_link_seq_start(struct seq_file * seq,loff_t * pos)13*9f883612SDmitrii Dolgov static void *bpf_link_seq_start(struct seq_file *seq, loff_t *pos)
14*9f883612SDmitrii Dolgov {
15*9f883612SDmitrii Dolgov struct bpf_iter_seq_link_info *info = seq->private;
16*9f883612SDmitrii Dolgov struct bpf_link *link;
17*9f883612SDmitrii Dolgov
18*9f883612SDmitrii Dolgov link = bpf_link_get_curr_or_next(&info->link_id);
19*9f883612SDmitrii Dolgov if (!link)
20*9f883612SDmitrii Dolgov return NULL;
21*9f883612SDmitrii Dolgov
22*9f883612SDmitrii Dolgov if (*pos == 0)
23*9f883612SDmitrii Dolgov ++*pos;
24*9f883612SDmitrii Dolgov return link;
25*9f883612SDmitrii Dolgov }
26*9f883612SDmitrii Dolgov
bpf_link_seq_next(struct seq_file * seq,void * v,loff_t * pos)27*9f883612SDmitrii Dolgov static void *bpf_link_seq_next(struct seq_file *seq, void *v, loff_t *pos)
28*9f883612SDmitrii Dolgov {
29*9f883612SDmitrii Dolgov struct bpf_iter_seq_link_info *info = seq->private;
30*9f883612SDmitrii Dolgov
31*9f883612SDmitrii Dolgov ++*pos;
32*9f883612SDmitrii Dolgov ++info->link_id;
33*9f883612SDmitrii Dolgov bpf_link_put((struct bpf_link *)v);
34*9f883612SDmitrii Dolgov return bpf_link_get_curr_or_next(&info->link_id);
35*9f883612SDmitrii Dolgov }
36*9f883612SDmitrii Dolgov
37*9f883612SDmitrii Dolgov struct bpf_iter__bpf_link {
38*9f883612SDmitrii Dolgov __bpf_md_ptr(struct bpf_iter_meta *, meta);
39*9f883612SDmitrii Dolgov __bpf_md_ptr(struct bpf_link *, link);
40*9f883612SDmitrii Dolgov };
41*9f883612SDmitrii Dolgov
DEFINE_BPF_ITER_FUNC(bpf_link,struct bpf_iter_meta * meta,struct bpf_link * link)42*9f883612SDmitrii Dolgov DEFINE_BPF_ITER_FUNC(bpf_link, struct bpf_iter_meta *meta, struct bpf_link *link)
43*9f883612SDmitrii Dolgov
44*9f883612SDmitrii Dolgov static int __bpf_link_seq_show(struct seq_file *seq, void *v, bool in_stop)
45*9f883612SDmitrii Dolgov {
46*9f883612SDmitrii Dolgov struct bpf_iter__bpf_link ctx;
47*9f883612SDmitrii Dolgov struct bpf_iter_meta meta;
48*9f883612SDmitrii Dolgov struct bpf_prog *prog;
49*9f883612SDmitrii Dolgov int ret = 0;
50*9f883612SDmitrii Dolgov
51*9f883612SDmitrii Dolgov ctx.meta = &meta;
52*9f883612SDmitrii Dolgov ctx.link = v;
53*9f883612SDmitrii Dolgov meta.seq = seq;
54*9f883612SDmitrii Dolgov prog = bpf_iter_get_info(&meta, in_stop);
55*9f883612SDmitrii Dolgov if (prog)
56*9f883612SDmitrii Dolgov ret = bpf_iter_run_prog(prog, &ctx);
57*9f883612SDmitrii Dolgov
58*9f883612SDmitrii Dolgov return ret;
59*9f883612SDmitrii Dolgov }
60*9f883612SDmitrii Dolgov
bpf_link_seq_show(struct seq_file * seq,void * v)61*9f883612SDmitrii Dolgov static int bpf_link_seq_show(struct seq_file *seq, void *v)
62*9f883612SDmitrii Dolgov {
63*9f883612SDmitrii Dolgov return __bpf_link_seq_show(seq, v, false);
64*9f883612SDmitrii Dolgov }
65*9f883612SDmitrii Dolgov
bpf_link_seq_stop(struct seq_file * seq,void * v)66*9f883612SDmitrii Dolgov static void bpf_link_seq_stop(struct seq_file *seq, void *v)
67*9f883612SDmitrii Dolgov {
68*9f883612SDmitrii Dolgov if (!v)
69*9f883612SDmitrii Dolgov (void)__bpf_link_seq_show(seq, v, true);
70*9f883612SDmitrii Dolgov else
71*9f883612SDmitrii Dolgov bpf_link_put((struct bpf_link *)v);
72*9f883612SDmitrii Dolgov }
73*9f883612SDmitrii Dolgov
74*9f883612SDmitrii Dolgov static const struct seq_operations bpf_link_seq_ops = {
75*9f883612SDmitrii Dolgov .start = bpf_link_seq_start,
76*9f883612SDmitrii Dolgov .next = bpf_link_seq_next,
77*9f883612SDmitrii Dolgov .stop = bpf_link_seq_stop,
78*9f883612SDmitrii Dolgov .show = bpf_link_seq_show,
79*9f883612SDmitrii Dolgov };
80*9f883612SDmitrii Dolgov
81*9f883612SDmitrii Dolgov BTF_ID_LIST(btf_bpf_link_id)
82*9f883612SDmitrii Dolgov BTF_ID(struct, bpf_link)
83*9f883612SDmitrii Dolgov
84*9f883612SDmitrii Dolgov static const struct bpf_iter_seq_info bpf_link_seq_info = {
85*9f883612SDmitrii Dolgov .seq_ops = &bpf_link_seq_ops,
86*9f883612SDmitrii Dolgov .init_seq_private = NULL,
87*9f883612SDmitrii Dolgov .fini_seq_private = NULL,
88*9f883612SDmitrii Dolgov .seq_priv_size = sizeof(struct bpf_iter_seq_link_info),
89*9f883612SDmitrii Dolgov };
90*9f883612SDmitrii Dolgov
91*9f883612SDmitrii Dolgov static struct bpf_iter_reg bpf_link_reg_info = {
92*9f883612SDmitrii Dolgov .target = "bpf_link",
93*9f883612SDmitrii Dolgov .ctx_arg_info_size = 1,
94*9f883612SDmitrii Dolgov .ctx_arg_info = {
95*9f883612SDmitrii Dolgov { offsetof(struct bpf_iter__bpf_link, link),
96*9f883612SDmitrii Dolgov PTR_TO_BTF_ID_OR_NULL },
97*9f883612SDmitrii Dolgov },
98*9f883612SDmitrii Dolgov .seq_info = &bpf_link_seq_info,
99*9f883612SDmitrii Dolgov };
100*9f883612SDmitrii Dolgov
bpf_link_iter_init(void)101*9f883612SDmitrii Dolgov static int __init bpf_link_iter_init(void)
102*9f883612SDmitrii Dolgov {
103*9f883612SDmitrii Dolgov bpf_link_reg_info.ctx_arg_info[0].btf_id = *btf_bpf_link_id;
104*9f883612SDmitrii Dolgov return bpf_iter_reg_target(&bpf_link_reg_info);
105*9f883612SDmitrii Dolgov }
106*9f883612SDmitrii Dolgov
107*9f883612SDmitrii Dolgov late_initcall(bpf_link_iter_init);
108