Unverified Commit 22bae0fc authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!798 bpf: support BPF_PROG_QUERY for progs attached to sockmap

Merge Pull Request from: @kwb0523 
 
Right now there is no way to query whether BPF programs are
attached to a sockmap or not.

we can use the standard interface in libbpf to query, such as:
bpf_prog_query(mapFd, BPF_SK_SKB_STREAM_PARSER, 0, NULL, ...);
the mapFd is the fd of sockmap. 
 
Link:https://gitee.com/openeuler/kernel/pulls/798

 

Reviewed-by: default avatarYue Haibing <yuehaibing@huawei.com>
Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 0c374437 05038388
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1880,6 +1880,7 @@ int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog);
int sock_map_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype);
int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value, u64 flags);
void sock_map_unhash(struct sock *sk);
int sock_map_bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr);
void sock_map_close(struct sock *sk, long timeout);
#else
static inline int sock_map_prog_update(struct bpf_map *map,
@@ -1906,6 +1907,12 @@ static inline int sock_map_update_elem_sys(struct bpf_map *map, void *key, void
{
	return -EOPNOTSUPP;
}

static inline int sock_map_bpf_prog_query(const union bpf_attr *attr,
					   union bpf_attr __user *uattr)
{
	return -EINVAL;
}
#endif /* CONFIG_BPF_STREAM_PARSER */

#if defined(CONFIG_INET) && defined(CONFIG_BPF_SYSCALL)
+4 −0
Original line number Diff line number Diff line
@@ -3136,6 +3136,10 @@ static int bpf_prog_query(const union bpf_attr *attr,
	case BPF_FLOW_DISSECTOR:
	case BPF_SK_LOOKUP:
		return netns_bpf_prog_query(attr, uattr);
	case BPF_SK_SKB_STREAM_PARSER:
	case BPF_SK_SKB_STREAM_VERDICT:
	case BPF_SK_MSG_VERDICT:
		return sock_map_bpf_prog_query(attr, uattr);
	default:
		return -EINVAL;
	}
+68 −6
Original line number Diff line number Diff line
@@ -1498,28 +1498,39 @@ static struct sk_psock_progs *sock_map_progs(struct bpf_map *map)
	return NULL;
}

int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog,
			 struct bpf_prog *old, u32 which)
int sock_map_prog_lookup(struct bpf_map *map, struct bpf_prog ***pprog,
			 u32 which)
{
	struct sk_psock_progs *progs = sock_map_progs(map);
	struct bpf_prog **pprog;

	if (!progs)
		return -EOPNOTSUPP;

	switch (which) {
	case BPF_SK_MSG_VERDICT:
		pprog = &progs->msg_parser;
		*pprog = &progs->msg_parser;
		break;
	case BPF_SK_SKB_STREAM_PARSER:
		pprog = &progs->skb_parser;
		*pprog = &progs->skb_parser;
		break;
	case BPF_SK_SKB_STREAM_VERDICT:
		pprog = &progs->skb_verdict;
		*pprog = &progs->skb_verdict;
		break;
	default:
		return -EOPNOTSUPP;
	}
	return 0;
}

int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog,
			 struct bpf_prog *old, u32 which)
{
	struct bpf_prog **pprog;
	int ret;

	ret = sock_map_prog_lookup(map, &pprog, which);
	if (ret)
		return ret;

	if (old)
		return psock_replace_prog(pprog, prog, old);
@@ -1528,6 +1539,57 @@ int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog,
	return 0;
}

int sock_map_bpf_prog_query(const union bpf_attr *attr,
			    union bpf_attr __user *uattr)
{
	__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
	u32 prog_cnt = 0, flags = 0, ufd = attr->target_fd;
	struct bpf_prog **pprog;
	struct bpf_prog *prog;
	struct bpf_map *map;
	struct fd f;
	u32 id = 0;
	int ret;

	if (attr->query.query_flags)
		return -EINVAL;

	f = fdget(ufd);
	map = __bpf_map_get(f);
	if (IS_ERR(map))
		return PTR_ERR(map);

	rcu_read_lock();

	ret = sock_map_prog_lookup(map, &pprog, attr->query.attach_type);
	if (ret)
		goto end;

	prog = *pprog;
	prog_cnt = !prog ? 0 : 1;

	if (!attr->query.prog_cnt || !prog_ids || !prog_cnt)
		goto end;

	/* we do not hold the refcnt, the bpf prog may be released
	 * asynchronously and the id would be set to 0.
	 */
	id = data_race(prog->aux->id);
	if (id == 0)
		prog_cnt = 0;

end:
	rcu_read_unlock();

	if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)) ||
	    (id != 0 && copy_to_user(prog_ids, &id, sizeof(u32))) ||
	    copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt)))
		ret = -EFAULT;

	fdput(f);
	return ret;
}

static void sock_map_unlink(struct sock *sk, struct sk_psock_link *link)
{
	switch (link->map->map_type) {