提交 d93afd18 编写于 作者: R Roman Gushchin 提交者: Zheng Zengkai

bpf: sched: basic infrastructure for scheduler bpf

maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I5F6X6
CVE: NA

Reference: https://lore.kernel.org/all/20210916162451.709260-1-guro@fb.com/

-------------------

This commit introduces basic definitions and infrastructure for
scheduler bpf programs. It defines the BPF_PROG_TYPE_SCHED program
type and the BPF_SCHED attachment type.

The implementation is inspired by lsm bpf programs and is based on
kretprobes. This will allow to add new hooks with a minimal changes to
the kernel code and without any changes to libbpf/bpftool.
It's very convenient as I anticipate a large number of private patches
being used for a long time before (or if at all) reaching upstream.

Sched programs are expected to return an int, which meaning will be
context defined.

This patch doesn't add any real scheduler hooks (only a stub), it will
be done by following patches in the series.

Scheduler bpf programs as now are very restricted in what they can do:
only the bpf_printk() helper is available. The scheduler context can
impose significant restrictions on what's safe and what's not. So
let's extend their abilities on case by case basis when a need arise.
Signed-off-by: NRoman Gushchin <guro@fb.com>
Signed-off-by: NChen Hui <judy.chenhui@huawei.com>
Signed-off-by: NRen Zhijie <renzhijie2@huawei.com>
上级 99d1d3bc
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_BPF_SCHED_H
#define _LINUX_BPF_SCHED_H
#include <linux/bpf.h>
#ifdef CONFIG_BPF_SCHED
#define BPF_SCHED_HOOK(RET, DEFAULT, NAME, ...) \
RET bpf_sched_##NAME(__VA_ARGS__);
#include <linux/sched_hook_defs.h>
#undef BPF_SCHED_HOOK
int bpf_sched_verify_prog(struct bpf_verifier_log *vlog,
const struct bpf_prog *prog);
#else /* !CONFIG_BPF_SCHED */
static inline int bpf_sched_verify_prog(struct bpf_verifier_log *vlog,
const struct bpf_prog *prog)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_BPF_SCHED */
#endif /* _LINUX_BPF_SCHED_H */
......@@ -77,6 +77,10 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm,
void *, void *)
#endif /* CONFIG_BPF_LSM */
#endif
#ifdef CONFIG_BPF_SCHED
BPF_PROG_TYPE(BPF_PROG_TYPE_SCHED, bpf_sched,
void *, void *)
#endif /* CONFIG_BPF_SCHED */
BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops)
......
/* SPDX-License-Identifier: GPL-2.0 */
BPF_SCHED_HOOK(int, 0, dummy, void)
......@@ -199,6 +199,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_EXT,
BPF_PROG_TYPE_LSM,
BPF_PROG_TYPE_SK_LOOKUP,
BPF_PROG_TYPE_SCHED,
};
enum bpf_attach_type {
......@@ -240,6 +241,7 @@ enum bpf_attach_type {
BPF_XDP_CPUMAP,
BPF_SK_LOOKUP,
BPF_XDP,
BPF_SCHED,
__MAX_BPF_ATTACH_TYPE
};
......
......@@ -1758,6 +1758,16 @@ config BPF_LSM
If you are unsure how to answer this question, answer N.
config BPF_SCHED
bool "SCHED Instrumentation with BPF"
depends on BPF_EVENTS
depends on BPF_SYSCALL
help
Enables instrumentation of the sched hooks with eBPF programs for
implementing dynamic scheduling policies.
If you are unsure how to answer this question, answer N.
config BPF_SYSCALL
bool "Enable bpf() system call"
select BPF
......
......@@ -4479,6 +4479,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
return true;
t = btf_type_by_id(btf, t->type);
break;
case BPF_SCHED:
case BPF_MODIFY_RETURN:
/* For now the BPF_MODIFY_RETURN can only be attached to
* functions that return an int.
......
......@@ -1997,6 +1997,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
case BPF_PROG_TYPE_LSM:
case BPF_PROG_TYPE_STRUCT_OPS:
case BPF_PROG_TYPE_EXT:
case BPF_PROG_TYPE_SCHED:
break;
default:
return -EINVAL;
......@@ -2108,6 +2109,7 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
case BPF_PROG_TYPE_LSM:
case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
case BPF_PROG_TYPE_EXT: /* extends any prog */
case BPF_PROG_TYPE_SCHED:
return true;
default:
return false;
......@@ -2608,6 +2610,12 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
goto out_put_prog;
}
break;
case BPF_PROG_TYPE_SCHED:
if (prog->expected_attach_type != BPF_SCHED) {
err = -EINVAL;
goto out_put_prog;
}
break;
default:
err = -EINVAL;
goto out_put_prog;
......@@ -2838,6 +2846,7 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
case BPF_PROG_TYPE_TRACING:
case BPF_PROG_TYPE_EXT:
case BPF_PROG_TYPE_LSM:
case BPF_PROG_TYPE_SCHED:
if (attr->raw_tracepoint.name) {
/* The attach point for this category of programs
* should be specified via btf_id during program load.
......
......@@ -357,6 +357,7 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
switch (prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
return BPF_TRAMP_FENTRY;
case BPF_SCHED:
case BPF_MODIFY_RETURN:
return BPF_TRAMP_MODIFY_RETURN;
case BPF_TRACE_FEXIT:
......
......@@ -22,6 +22,7 @@
#include <linux/error-injection.h>
#include <linux/bpf_lsm.h>
#include <linux/btf_ids.h>
#include <linux/bpf_sched.h>
#include "disasm.h"
......@@ -12178,6 +12179,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
case BPF_LSM_MAC:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_SCHED:
if (!btf_type_is_func(t)) {
bpf_log(log, "attach_btf_id %u is not a function\n",
btf_id);
......@@ -12283,7 +12285,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
if (prog->type != BPF_PROG_TYPE_TRACING &&
prog->type != BPF_PROG_TYPE_LSM &&
prog->type != BPF_PROG_TYPE_EXT)
prog->type != BPF_PROG_TYPE_EXT &&
prog->type != BPF_PROG_TYPE_SCHED)
return 0;
ret = bpf_check_attach_target(&env->log, prog, tgt_prog, btf_id, &tgt_info);
......@@ -12323,6 +12326,12 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
return ret;
}
if (prog->type == BPF_PROG_TYPE_SCHED) {
ret = bpf_sched_verify_prog(&env->log, prog);
if (ret < 0)
return ret;
}
key = bpf_trampoline_compute_key(tgt_prog, btf_id);
tr = bpf_trampoline_get(key, &tgt_info);
if (!tr)
......
......@@ -36,3 +36,4 @@ obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
obj-$(CONFIG_MEMBARRIER) += membarrier.o
obj-$(CONFIG_CPU_ISOLATION) += isolation.o
obj-$(CONFIG_PSI) += psi.o
obj-$(CONFIG_BPF_SCHED) += bpf_sched.o
\ No newline at end of file
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <linux/cgroup.h>
#include <linux/bpf_verifier.h>
#include <linux/bpf_sched.h>
#include <linux/btf_ids.h>
#include "sched.h"
/*
* For every hook declare a nop function where a BPF program can be attached.
*/
#define BPF_SCHED_HOOK(RET, DEFAULT, NAME, ...) \
noinline RET bpf_sched_##NAME(__VA_ARGS__) \
{ \
return DEFAULT; \
}
#include <linux/sched_hook_defs.h>
#undef BPF_SCHED_HOOK
#define BPF_SCHED_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_sched_##NAME)
BTF_SET_START(bpf_sched_hooks)
#include <linux/sched_hook_defs.h>
#undef BPF_SCHED_HOOK
BTF_SET_END(bpf_sched_hooks)
int bpf_sched_verify_prog(struct bpf_verifier_log *vlog,
const struct bpf_prog *prog)
{
if (!prog->gpl_compatible) {
bpf_log(vlog,
"sched programs must have a GPL compatible license\n");
return -EINVAL;
}
if (!btf_id_set_contains(&bpf_sched_hooks, prog->aux->attach_btf_id)) {
bpf_log(vlog, "attach_btf_id %u points to wrong type name %s\n",
prog->aux->attach_btf_id, prog->aux->attach_func_name);
return -EINVAL;
}
return 0;
}
static const struct bpf_func_proto *
bpf_sched_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
switch (func_id) {
case BPF_FUNC_trace_printk:
return bpf_get_trace_printk_proto();
default:
return NULL;
}
}
const struct bpf_prog_ops bpf_sched_prog_ops = {
};
const struct bpf_verifier_ops bpf_sched_verifier_ops = {
.get_func_proto = bpf_sched_func_proto,
.is_valid_access = btf_ctx_access,
};
......@@ -199,6 +199,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_EXT,
BPF_PROG_TYPE_LSM,
BPF_PROG_TYPE_SK_LOOKUP,
BPF_PROG_TYPE_SCHED,
};
enum bpf_attach_type {
......@@ -240,6 +241,7 @@ enum bpf_attach_type {
BPF_XDP_CPUMAP,
BPF_SK_LOOKUP,
BPF_XDP,
BPF_SCHED,
__MAX_BPF_ATTACH_TYPE
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册