Commit eaa6bcb7 authored by Hao Luo's avatar Hao Luo Committed by Alexei Starovoitov
Browse files

bpf: Introduce bpf_per_cpu_ptr()



Add bpf_per_cpu_ptr() to help bpf programs access percpu vars.
bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the kernel
except that it may return NULL. This happens when the cpu parameter is
out of range. So the caller must check the returned value.

Signed-off-by: default avatarHao Luo <haoluo@google.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200929235049.2533242-5-haoluo@google.com
parent 2c2f6abe
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@ enum bpf_arg_type {
	ARG_PTR_TO_ALLOC_MEM_OR_NULL,	/* pointer to dynamically allocated memory or NULL */
	ARG_CONST_ALLOC_SIZE_OR_ZERO,	/* number of allocated bytes requested */
	ARG_PTR_TO_BTF_ID_SOCK_COMMON,	/* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */
	ARG_PTR_TO_PERCPU_BTF_ID,	/* pointer to in-kernel percpu type */
	__BPF_ARG_TYPE_MAX,
};

@@ -307,6 +308,7 @@ enum bpf_return_type {
	RET_PTR_TO_SOCK_COMMON_OR_NULL,	/* returns a pointer to a sock_common or NULL */
	RET_PTR_TO_ALLOC_MEM_OR_NULL,	/* returns a pointer to dynamically allocated memory or NULL */
	RET_PTR_TO_BTF_ID_OR_NULL,	/* returns a pointer to a btf_id or NULL */
	RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */
};

/* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
@@ -405,6 +407,7 @@ enum bpf_reg_type {
	PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */
	PTR_TO_RDWR_BUF,	 /* reg points to a read/write buffer */
	PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */
	PTR_TO_PERCPU_BTF_ID,	 /* reg points to a percpu kernel variable */
};

/* The information passed from prog-specific *_is_valid_access
@@ -1828,6 +1831,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
extern const struct bpf_func_proto bpf_copy_from_user_proto;
extern const struct bpf_func_proto bpf_snprintf_btf_proto;
extern const struct bpf_func_proto bpf_per_cpu_ptr_proto;

const struct bpf_func_proto *bpf_tracing_func_proto(
	enum bpf_func_id func_id, const struct bpf_prog *prog);
+11 −0
Original line number Diff line number Diff line
@@ -110,6 +110,11 @@ btf_resolve_size(const struct btf *btf, const struct btf_type *type,
	     i < btf_type_vlen(struct_type);			\
	     i++, member++)

#define for_each_vsi(i, datasec_type, member)			\
	for (i = 0, member = btf_type_var_secinfo(datasec_type);	\
	     i < btf_type_vlen(datasec_type);			\
	     i++, member++)

static inline bool btf_type_is_ptr(const struct btf_type *t)
{
	return BTF_INFO_KIND(t->info) == BTF_KIND_PTR;
@@ -194,6 +199,12 @@ static inline const struct btf_member *btf_type_member(const struct btf_type *t)
	return (const struct btf_member *)(t + 1);
}

static inline const struct btf_var_secinfo *btf_type_var_secinfo(
		const struct btf_type *t)
{
	return (const struct btf_var_secinfo *)(t + 1);
}

#ifdef CONFIG_BPF_SYSCALL
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
const char *btf_name_by_offset(const struct btf *btf, u32 offset);
+18 −0
Original line number Diff line number Diff line
@@ -3686,6 +3686,23 @@ union bpf_attr {
 * 	Return
 * 		The helper returns **TC_ACT_REDIRECT** on success or
 * 		**TC_ACT_SHOT** on error.
 *
 * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu)
 *     Description
 *             Take a pointer to a percpu ksym, *percpu_ptr*, and return a
 *             pointer to the percpu kernel variable on *cpu*. A ksym is an
 *             extern variable decorated with '__ksym'. For ksym, there is a
 *             global var (either static or global) defined of the same name
 *             in the kernel. The ksym is percpu if the global var is percpu.
 *             The returned pointer points to the global percpu var on *cpu*.
 *
 *             bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the
 *             kernel, except that bpf_per_cpu_ptr() may return NULL. This
 *             happens if *cpu* is larger than nr_cpu_ids. The caller of
 *             bpf_per_cpu_ptr() must check the returned value.
 *     Return
 *             A pointer pointing to the kernel percpu variable on *cpu*, or
 *             NULL, if *cpu* is invalid.
 */
#define __BPF_FUNC_MAPPER(FN)		\
	FN(unspec),			\
@@ -3841,6 +3858,7 @@ union bpf_attr {
	FN(seq_printf_btf),		\
	FN(skb_cgroup_classid),		\
	FN(redirect_neigh),		\
	FN(bpf_per_cpu_ptr),            \
	/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+0 −10
Original line number Diff line number Diff line
@@ -188,11 +188,6 @@
	     i < btf_type_vlen(struct_type);				\
	     i++, member++)

#define for_each_vsi(i, struct_type, member)			\
	for (i = 0, member = btf_type_var_secinfo(struct_type);	\
	     i < btf_type_vlen(struct_type);			\
	     i++, member++)

#define for_each_vsi_from(i, from, struct_type, member)				\
	for (i = from, member = btf_type_var_secinfo(struct_type) + from;	\
	     i < btf_type_vlen(struct_type);					\
@@ -598,11 +593,6 @@ static const struct btf_var *btf_type_var(const struct btf_type *t)
	return (const struct btf_var *)(t + 1);
}

static const struct btf_var_secinfo *btf_type_var_secinfo(const struct btf_type *t)
{
	return (const struct btf_var_secinfo *)(t + 1);
}

static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
{
	return kind_ops[BTF_INFO_KIND(t->info)];
+18 −0
Original line number Diff line number Diff line
@@ -623,6 +623,22 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {
	.arg3_type	= ARG_ANYTHING,
};

BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
{
	if (cpu >= nr_cpu_ids)
		return (unsigned long)NULL;

	return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu);
}

const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
	.func		= bpf_per_cpu_ptr,
	.gpl_only	= false,
	.ret_type	= RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL,
	.arg1_type	= ARG_PTR_TO_PERCPU_BTF_ID,
	.arg2_type	= ARG_ANYTHING,
};

const struct bpf_func_proto bpf_get_current_task_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
@@ -689,6 +705,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
		return &bpf_snprintf_btf_proto;
	case BPF_FUNC_jiffies64:
		return &bpf_jiffies64_proto;
	case BPF_FUNC_bpf_per_cpu_ptr:
		return &bpf_per_cpu_ptr_proto;
	default:
		break;
	}
Loading