aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeliang Tang <tanggeliang@kylinos.cn>2024-04-20 09:25:08 +0000
committerMatthieu Baerts (NGI0) <matttbe@kernel.org>2024-04-20 09:25:08 +0000
commit354a9aa042fe41e4f84814d056c24824f6c90572 (patch)
tree3d95f50a18d3d454b3d5ccde897a2c1d29559b4b
parent726ca47fe6d0da34277c36ee249ff9c5973e7090 (diff)
downloadmptcp_net-next-354a9aa042fe41e4f84814d056c24824f6c90572.tar.gz
bpf: Add bpf_mptcp_sched_ops
This patch implements a new struct bpf_struct_ops: bpf_mptcp_sched_ops. Register and unregister the bpf scheduler in .reg and .unreg. Add write access for the scheduled flag of struct mptcp_subflow_context in .btf_struct_access. This MPTCP BPF scheduler implementation is similar to BPF TCP CC. And net/ipv4/bpf_tcp_ca.c is a frame of reference for this patch. Acked-by: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Mat Martineau <martineau@kernel.org> Co-developed-by: Matthieu Baerts <matttbe@kernel.org> Signed-off-by: Matthieu Baerts <matttbe@kernel.org> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
-rw-r--r--net/mptcp/bpf.c176
1 files changed, 175 insertions, 1 deletions
diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
index c3d62535eb0cf2..4278158193f5a2 100644
--- a/net/mptcp/bpf.c
+++ b/net/mptcp/bpf.c
@@ -10,8 +10,175 @@
#define pr_fmt(fmt) "MPTCP: " fmt
#include <linux/bpf.h>
+#include <linux/bpf_verifier.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <net/bpf_sk_storage.h>
#include "protocol.h"
+#ifdef CONFIG_BPF_JIT
+static struct bpf_struct_ops bpf_mptcp_sched_ops;
+static const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly;
+static u32 mptcp_sock_id, mptcp_subflow_id;
+
+static const struct bpf_func_proto *
+bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id,
+ const struct bpf_prog *prog)
+{
+ switch (func_id) {
+ case BPF_FUNC_sk_storage_get:
+ return &bpf_sk_storage_get_proto;
+ case BPF_FUNC_sk_storage_delete:
+ return &bpf_sk_storage_delete_proto;
+ case BPF_FUNC_skc_to_tcp6_sock:
+ return &bpf_skc_to_tcp6_sock_proto;
+ case BPF_FUNC_skc_to_tcp_sock:
+ return &bpf_skc_to_tcp_sock_proto;
+ default:
+ return bpf_base_func_proto(func_id, prog);
+ }
+}
+
+static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
+ const struct bpf_reg_state *reg,
+ int off, int size)
+{
+ const struct btf_type *t;
+ size_t end;
+
+ t = btf_type_by_id(reg->btf, reg->btf_id);
+ if (t != mptcp_sock_type && t != mptcp_subflow_type) {
+ bpf_log(log, "only access to mptcp sock or subflow is supported\n");
+ return -EACCES;
+ }
+
+ switch (off) {
+ case offsetof(struct mptcp_sock, snd_burst):
+ end = offsetofend(struct mptcp_sock, snd_burst);
+ break;
+ case offsetof(struct mptcp_subflow_context, scheduled):
+ end = offsetofend(struct mptcp_subflow_context, scheduled);
+ break;
+ case offsetof(struct mptcp_subflow_context, avg_pacing_rate):
+ end = offsetofend(struct mptcp_subflow_context, avg_pacing_rate);
+ break;
+ default:
+ bpf_log(log, "no write support to %s at off %d\n",
+ t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context", off);
+ return -EACCES;
+ }
+
+ if (off + size > end) {
+ bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
+ t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context",
+ off, size, end);
+ return -EACCES;
+ }
+
+ return NOT_INIT;
+}
+
+static const struct bpf_verifier_ops bpf_mptcp_sched_verifier_ops = {
+ .get_func_proto = bpf_mptcp_sched_get_func_proto,
+ .is_valid_access = bpf_tracing_btf_ctx_access,
+ .btf_struct_access = bpf_mptcp_sched_btf_struct_access,
+};
+
+static int bpf_mptcp_sched_reg(void *kdata)
+{
+ return mptcp_register_scheduler(kdata);
+}
+
+static void bpf_mptcp_sched_unreg(void *kdata)
+{
+ mptcp_unregister_scheduler(kdata);
+}
+
+static int bpf_mptcp_sched_check_member(const struct btf_type *t,
+ const struct btf_member *member,
+ const struct bpf_prog *prog)
+{
+ return 0;
+}
+
+static int bpf_mptcp_sched_init_member(const struct btf_type *t,
+ const struct btf_member *member,
+ void *kdata, const void *udata)
+{
+ const struct mptcp_sched_ops *usched;
+ struct mptcp_sched_ops *sched;
+ u32 moff;
+
+ usched = (const struct mptcp_sched_ops *)udata;
+ sched = (struct mptcp_sched_ops *)kdata;
+
+ moff = __btf_member_bit_offset(t, member) / 8;
+ switch (moff) {
+ case offsetof(struct mptcp_sched_ops, name):
+ if (bpf_obj_name_cpy(sched->name, usched->name,
+ sizeof(sched->name)) <= 0)
+ return -EINVAL;
+ if (mptcp_sched_find(usched->name))
+ return -EEXIST;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int bpf_mptcp_sched_init(struct btf *btf)
+{
+ s32 type_id;
+
+ type_id = btf_find_by_name_kind(btf, "mptcp_sock",
+ BTF_KIND_STRUCT);
+ if (type_id < 0)
+ return -EINVAL;
+ mptcp_sock_id = type_id;
+ mptcp_sock_type = btf_type_by_id(btf, mptcp_sock_id);
+
+ type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
+ BTF_KIND_STRUCT);
+ if (type_id < 0)
+ return -EINVAL;
+ mptcp_subflow_id = type_id;
+ mptcp_subflow_type = btf_type_by_id(btf, mptcp_subflow_id);
+
+ return 0;
+}
+
+static int __bpf_mptcp_sched_get_subflow(struct mptcp_sock *msk,
+ struct mptcp_sched_data *data)
+{
+ return 0;
+}
+
+static void __bpf_mptcp_sched_init(struct mptcp_sock *msk)
+{
+}
+
+static void __bpf_mptcp_sched_release(struct mptcp_sock *msk)
+{
+}
+
+static struct mptcp_sched_ops __bpf_mptcp_sched_ops = {
+ .get_subflow = __bpf_mptcp_sched_get_subflow,
+ .init = __bpf_mptcp_sched_init,
+ .release = __bpf_mptcp_sched_release,
+};
+
+static struct bpf_struct_ops bpf_mptcp_sched_ops = {
+ .verifier_ops = &bpf_mptcp_sched_verifier_ops,
+ .reg = bpf_mptcp_sched_reg,
+ .unreg = bpf_mptcp_sched_unreg,
+ .check_member = bpf_mptcp_sched_check_member,
+ .init_member = bpf_mptcp_sched_init_member,
+ .init = bpf_mptcp_sched_init,
+ .name = "mptcp_sched_ops",
+ .cfi_stubs = &__bpf_mptcp_sched_ops,
+};
+#endif /* CONFIG_BPF_JIT */
+
struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
{
if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
@@ -45,6 +212,13 @@ __diag_pop();
static int __init bpf_mptcp_kfunc_init(void)
{
- return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
+ int ret;
+
+ ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
+#ifdef CONFIG_BPF_JIT
+ ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
+#endif
+
+ return ret;
}
late_initcall(bpf_mptcp_kfunc_init);