static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg) { struct bpf_prog *fp; char *name = NULL; u32 bpf_fd; bpf_fd = nla_get_u32(tb[TCA_ACT_BPF_FD]); fp = bpf_prog_get(bpf_fd); if (IS_ERR(fp)) return PTR_ERR(fp); if (fp->type != BPF_PROG_TYPE_SCHED_ACT) { bpf_prog_put(fp); return -EINVAL; } if (tb[TCA_ACT_BPF_NAME]) { name = kmemdup(nla_data(tb[TCA_ACT_BPF_NAME]), nla_len(tb[TCA_ACT_BPF_NAME]), GFP_KERNEL); if (!name) { bpf_prog_put(fp); return -ENOMEM; } } cfg->bpf_fd = bpf_fd; cfg->bpf_name = name; cfg->filter = fp; return 0; }
/* only called from syscall */ static int prog_array_map_update_elem(struct bpf_map *map, void *key, void *value, u64 map_flags) { struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_prog *prog, *old_prog; u32 index = *(u32 *)key, ufd; if (map_flags != BPF_ANY) return -EINVAL; if (index >= array->map.max_entries) return -E2BIG; ufd = *(u32 *)value; prog = bpf_prog_get(ufd); if (IS_ERR(prog)) return PTR_ERR(prog); if (!bpf_prog_array_compatible(array, prog)) { bpf_prog_put(prog); return -EINVAL; } old_prog = xchg(array->prog + index, prog); if (old_prog) bpf_prog_put_rcu(old_prog); return 0; }
static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type) { void *raw; *type = BPF_TYPE_MAP; raw = bpf_map_get_with_uref(ufd); if (IS_ERR(raw)) { *type = BPF_TYPE_PROG; raw = bpf_prog_get(ufd); } return raw; }
static void *prog_fd_array_get_ptr(struct bpf_map *map, int fd) { struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_prog *prog = bpf_prog_get(fd); if (IS_ERR(prog)) return prog; if (!bpf_prog_array_compatible(array, prog)) { bpf_prog_put(prog); return ERR_PTR(-EINVAL); } return prog; }