123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // SPDX-License-Identifier: GPL-2.0-only
- /* Copyright (c) 2020 Facebook */
- #include <linux/bpf.h>
- #include <linux/fs.h>
- #include <linux/filter.h>
- #include <linux/kernel.h>
- #include <linux/btf_ids.h>
- struct bpf_iter_seq_map_info {
- u32 map_id;
- };
- static void *bpf_map_seq_start(struct seq_file *seq, loff_t *pos)
- {
- struct bpf_iter_seq_map_info *info = seq->private;
- struct bpf_map *map;
- map = bpf_map_get_curr_or_next(&info->map_id);
- if (!map)
- return NULL;
- if (*pos == 0)
- ++*pos;
- return map;
- }
- static void *bpf_map_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
- struct bpf_iter_seq_map_info *info = seq->private;
- ++*pos;
- ++info->map_id;
- bpf_map_put((struct bpf_map *)v);
- return bpf_map_get_curr_or_next(&info->map_id);
- }
- struct bpf_iter__bpf_map {
- __bpf_md_ptr(struct bpf_iter_meta *, meta);
- __bpf_md_ptr(struct bpf_map *, map);
- };
- DEFINE_BPF_ITER_FUNC(bpf_map, struct bpf_iter_meta *meta, struct bpf_map *map)
- static int __bpf_map_seq_show(struct seq_file *seq, void *v, bool in_stop)
- {
- struct bpf_iter__bpf_map ctx;
- struct bpf_iter_meta meta;
- struct bpf_prog *prog;
- int ret = 0;
- ctx.meta = &meta;
- ctx.map = v;
- meta.seq = seq;
- prog = bpf_iter_get_info(&meta, in_stop);
- if (prog)
- ret = bpf_iter_run_prog(prog, &ctx);
- return ret;
- }
- static int bpf_map_seq_show(struct seq_file *seq, void *v)
- {
- return __bpf_map_seq_show(seq, v, false);
- }
- static void bpf_map_seq_stop(struct seq_file *seq, void *v)
- {
- if (!v)
- (void)__bpf_map_seq_show(seq, v, true);
- else
- bpf_map_put((struct bpf_map *)v);
- }
- static const struct seq_operations bpf_map_seq_ops = {
- .start = bpf_map_seq_start,
- .next = bpf_map_seq_next,
- .stop = bpf_map_seq_stop,
- .show = bpf_map_seq_show,
- };
- BTF_ID_LIST(btf_bpf_map_id)
- BTF_ID(struct, bpf_map)
- static const struct bpf_iter_seq_info bpf_map_seq_info = {
- .seq_ops = &bpf_map_seq_ops,
- .init_seq_private = NULL,
- .fini_seq_private = NULL,
- .seq_priv_size = sizeof(struct bpf_iter_seq_map_info),
- };
- static struct bpf_iter_reg bpf_map_reg_info = {
- .target = "bpf_map",
- .ctx_arg_info_size = 1,
- .ctx_arg_info = {
- { offsetof(struct bpf_iter__bpf_map, map),
- PTR_TO_BTF_ID_OR_NULL },
- },
- .seq_info = &bpf_map_seq_info,
- };
- static int bpf_iter_attach_map(struct bpf_prog *prog,
- union bpf_iter_link_info *linfo,
- struct bpf_iter_aux_info *aux)
- {
- u32 key_acc_size, value_acc_size, key_size, value_size;
- struct bpf_map *map;
- bool is_percpu = false;
- int err = -EINVAL;
- if (!linfo->map.map_fd)
- return -EBADF;
- map = bpf_map_get_with_uref(linfo->map.map_fd);
- if (IS_ERR(map))
- return PTR_ERR(map);
- if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
- is_percpu = true;
- else if (map->map_type != BPF_MAP_TYPE_HASH &&
- map->map_type != BPF_MAP_TYPE_LRU_HASH &&
- map->map_type != BPF_MAP_TYPE_ARRAY)
- goto put_map;
- key_acc_size = prog->aux->max_rdonly_access;
- value_acc_size = prog->aux->max_rdwr_access;
- key_size = map->key_size;
- if (!is_percpu)
- value_size = map->value_size;
- else
- value_size = round_up(map->value_size, 8) * num_possible_cpus();
- if (key_acc_size > key_size || value_acc_size > value_size) {
- err = -EACCES;
- goto put_map;
- }
- aux->map = map;
- return 0;
- put_map:
- bpf_map_put_with_uref(map);
- return err;
- }
- static void bpf_iter_detach_map(struct bpf_iter_aux_info *aux)
- {
- 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,
- struct bpf_map *map, void *key, void *value)
- static const struct bpf_iter_reg bpf_map_elem_reg_info = {
- .target = "bpf_map_elem",
- .attach_target = bpf_iter_attach_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 = {
- { offsetof(struct bpf_iter__bpf_map_elem, key),
- PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY },
- { offsetof(struct bpf_iter__bpf_map_elem, value),
- PTR_TO_BUF | PTR_MAYBE_NULL },
- },
- };
- static int __init bpf_map_iter_init(void)
- {
- int ret;
- bpf_map_reg_info.ctx_arg_info[0].btf_id = *btf_bpf_map_id;
- ret = bpf_iter_reg_target(&bpf_map_reg_info);
- if (ret)
- return ret;
- return bpf_iter_reg_target(&bpf_map_elem_reg_info);
- }
- late_initcall(bpf_map_iter_init);
|