Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /* Multipath TCP
3 : : *
4 : : * Copyright (c) 2020, Tessares SA.
5 : : * Copyright (c) 2022, SUSE.
6 : : *
7 : : * Author: Nicolas Rybowski <nicolas.rybowski@tessares.net>
8 : : */
9 : :
10 : : #define pr_fmt(fmt) "MPTCP: " fmt
11 : :
12 : : #include <linux/bpf.h>
13 : : #include <linux/bpf_verifier.h>
14 : : #include <linux/btf.h>
15 : : #include <linux/btf_ids.h>
16 : : #include <net/bpf_sk_storage.h>
17 : : #include "protocol.h"
18 : :
19 : : #ifdef CONFIG_BPF_JIT
20 : : static struct bpf_struct_ops bpf_mptcp_sched_ops;
21 : : static const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly;
22 : : static u32 mptcp_sock_id, mptcp_subflow_id;
23 : :
24 : : static const struct bpf_func_proto *
25 : 2670 : bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id,
26 : : const struct bpf_prog *prog)
27 : : {
28 [ + - + + : 2670 : switch (func_id) {
+ ]
29 : : case BPF_FUNC_sk_storage_get:
30 : : return &bpf_sk_storage_get_proto;
31 : 18 : case BPF_FUNC_sk_storage_delete:
32 : 18 : return &bpf_sk_storage_delete_proto;
33 : 0 : case BPF_FUNC_skc_to_tcp6_sock:
34 : 0 : return &bpf_skc_to_tcp6_sock_proto;
35 : 2496 : case BPF_FUNC_skc_to_tcp_sock:
36 : 2496 : return &bpf_skc_to_tcp_sock_proto;
37 : 120 : default:
38 : 120 : return bpf_base_func_proto(func_id, prog);
39 : : }
40 : : }
41 : :
42 : 178 : static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
43 : : const struct bpf_reg_state *reg,
44 : : int off, int size)
45 : : {
46 : 178 : const struct btf_type *t;
47 : 178 : size_t end;
48 : :
49 : 178 : t = btf_type_by_id(reg->btf, reg->btf_id);
50 : :
51 [ + + ]: 178 : if (t == mptcp_sock_type) {
52 [ - + ]: 10 : switch (off) {
53 : : case offsetof(struct mptcp_sock, snd_burst):
54 : : end = offsetofend(struct mptcp_sock, snd_burst);
55 : : break;
56 : 0 : default:
57 : 0 : bpf_log(log, "no write support to mptcp_sock at off %d\n",
58 : : off);
59 : 0 : return -EACCES;
60 : : }
61 [ + - ]: 168 : } else if (t == mptcp_subflow_type) {
62 [ - + ]: 168 : switch (off) {
63 : : case offsetof(struct mptcp_subflow_context, avg_pacing_rate):
64 : : end = offsetofend(struct mptcp_subflow_context, avg_pacing_rate);
65 : : break;
66 : 0 : default:
67 : 0 : bpf_log(log, "no write support to mptcp_subflow_context at off %d\n",
68 : : off);
69 : 0 : return -EACCES;
70 : : }
71 : : } else {
72 : 0 : bpf_log(log, "only access to mptcp sock or subflow is supported\n");
73 : 0 : return -EACCES;
74 : : }
75 : :
76 [ - + ]: 178 : if (off + size > end) {
77 [ # # ]: 0 : bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
78 : : t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context",
79 : : off, size, end);
80 : 0 : return -EACCES;
81 : : }
82 : :
83 : : return NOT_INIT;
84 : : }
85 : :
86 : : static const struct bpf_verifier_ops bpf_mptcp_sched_verifier_ops = {
87 : : .get_func_proto = bpf_mptcp_sched_get_func_proto,
88 : : .is_valid_access = bpf_tracing_btf_ctx_access,
89 : : .btf_struct_access = bpf_mptcp_sched_btf_struct_access,
90 : : };
91 : :
92 : 30 : static int bpf_mptcp_sched_reg(void *kdata, struct bpf_link *link)
93 : : {
94 : 30 : return mptcp_register_scheduler(kdata);
95 : : }
96 : :
97 : 30 : static void bpf_mptcp_sched_unreg(void *kdata, struct bpf_link *link)
98 : : {
99 : 30 : mptcp_unregister_scheduler(kdata);
100 : 30 : }
101 : :
102 : 90 : static int bpf_mptcp_sched_check_member(const struct btf_type *t,
103 : : const struct btf_member *member,
104 : : const struct bpf_prog *prog)
105 : : {
106 : 90 : return 0;
107 : : }
108 : :
109 : 150 : static int bpf_mptcp_sched_init_member(const struct btf_type *t,
110 : : const struct btf_member *member,
111 : : void *kdata, const void *udata)
112 : : {
113 : 150 : const struct mptcp_sched_ops *usched;
114 : 150 : struct mptcp_sched_ops *sched;
115 : 150 : u32 moff;
116 : 150 : int ret;
117 : :
118 : 150 : usched = (const struct mptcp_sched_ops *)udata;
119 : 150 : sched = (struct mptcp_sched_ops *)kdata;
120 : :
121 [ - + ]: 150 : moff = __btf_member_bit_offset(t, member) / 8;
122 [ + + ]: 150 : switch (moff) {
123 : 30 : case offsetof(struct mptcp_sched_ops, name):
124 [ + - ]: 30 : if (bpf_obj_name_cpy(sched->name, usched->name,
125 : : sizeof(sched->name)) <= 0)
126 : : return -EINVAL;
127 : :
128 : 30 : rcu_read_lock();
129 [ + - ]: 30 : ret = mptcp_sched_find(usched->name) ? -EEXIST : 1;
130 : 30 : rcu_read_unlock();
131 : :
132 : 30 : return ret;
133 : : }
134 : :
135 : : return 0;
136 : : }
137 : :
138 : 2 : static int bpf_mptcp_sched_init(struct btf *btf)
139 : : {
140 : 2 : s32 type_id;
141 : :
142 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_sock",
143 : : BTF_KIND_STRUCT);
144 [ - + ]: 2 : if (type_id < 0)
145 : : return -EINVAL;
146 : 2 : mptcp_sock_id = type_id;
147 : 2 : mptcp_sock_type = btf_type_by_id(btf, mptcp_sock_id);
148 : :
149 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
150 : : BTF_KIND_STRUCT);
151 [ - + ]: 2 : if (type_id < 0)
152 : : return -EINVAL;
153 : 2 : mptcp_subflow_id = type_id;
154 : 2 : mptcp_subflow_type = btf_type_by_id(btf, mptcp_subflow_id);
155 : :
156 : 2 : return 0;
157 : : }
158 : :
159 : 0 : static int __bpf_mptcp_sched_get_subflow(struct mptcp_sock *msk,
160 : : struct mptcp_sched_data *data)
161 : : {
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static void __bpf_mptcp_sched_init(struct mptcp_sock *msk)
166 : : {
167 : 0 : }
168 : :
169 : 0 : static void __bpf_mptcp_sched_release(struct mptcp_sock *msk)
170 : : {
171 : 0 : }
172 : :
173 : : static struct mptcp_sched_ops __bpf_mptcp_sched_ops = {
174 : : .get_subflow = __bpf_mptcp_sched_get_subflow,
175 : : .init = __bpf_mptcp_sched_init,
176 : : .release = __bpf_mptcp_sched_release,
177 : : };
178 : :
179 : : static struct bpf_struct_ops bpf_mptcp_sched_ops = {
180 : : .verifier_ops = &bpf_mptcp_sched_verifier_ops,
181 : : .reg = bpf_mptcp_sched_reg,
182 : : .unreg = bpf_mptcp_sched_unreg,
183 : : .check_member = bpf_mptcp_sched_check_member,
184 : : .init_member = bpf_mptcp_sched_init_member,
185 : : .init = bpf_mptcp_sched_init,
186 : : .name = "mptcp_sched_ops",
187 : : .cfi_stubs = &__bpf_mptcp_sched_ops,
188 : : };
189 : : #endif /* CONFIG_BPF_JIT */
190 : :
191 : 18 : struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
192 : : {
193 [ + - + + : 27 : if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
+ + + + ]
194 [ - + ]: 18 : return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
195 : :
196 : : return NULL;
197 : : }
198 : :
199 : : BTF_SET8_START(bpf_mptcp_fmodret_ids)
200 : : BTF_ID_FLAGS(func, update_socket_protocol)
201 : : BTF_SET8_END(bpf_mptcp_fmodret_ids)
202 : :
203 : : static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
204 : : .owner = THIS_MODULE,
205 : : .set = &bpf_mptcp_fmodret_ids,
206 : : };
207 : :
208 : : __diag_push();
209 : : __diag_ignore_all("-Wmissing-prototypes",
210 : : "kfuncs which will be used in BPF programs");
211 : :
212 : : __bpf_kfunc struct mptcp_subflow_context *
213 : 543481 : bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
214 : : {
215 [ + - ]: 543481 : if (pos >= MPTCP_SUBFLOWS_MAX)
216 : : return NULL;
217 : 543481 : return data->contexts[pos];
218 : : }
219 : :
220 : 12 : __bpf_kfunc bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
221 : : {
222 : 12 : return tcp_rtx_queue_empty(sk);
223 : : }
224 : :
225 : : __diag_pop();
226 : :
227 : : BTF_KFUNCS_START(bpf_mptcp_sched_kfunc_ids)
228 : : BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
229 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
230 : : BTF_ID_FLAGS(func, mptcp_subflow_active)
231 : : BTF_ID_FLAGS(func, mptcp_set_timeout)
232 : : BTF_ID_FLAGS(func, mptcp_wnd_end)
233 : : BTF_ID_FLAGS(func, tcp_stream_memory_free)
234 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
235 : : BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale)
236 : : BTF_KFUNCS_END(bpf_mptcp_sched_kfunc_ids)
237 : :
238 : : static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
239 : : .owner = THIS_MODULE,
240 : : .set = &bpf_mptcp_sched_kfunc_ids,
241 : : };
242 : :
243 : 4 : static int __init bpf_mptcp_kfunc_init(void)
244 : : {
245 : 4 : int ret;
246 : :
247 : 4 : ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
248 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
249 : : &bpf_mptcp_sched_kfunc_set);
250 : : #ifdef CONFIG_BPF_JIT
251 [ + - ]: 4 : ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
252 : : #endif
253 : :
254 : 4 : return ret;
255 : : }
256 : : late_initcall(bpf_mptcp_kfunc_init);
|