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 : 170 : 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 : 170 : const struct btf_type *t;
47 : 170 : size_t end;
48 : :
49 : 170 : t = btf_type_by_id(reg->btf, reg->btf_id);
50 : :
51 [ + + ]: 170 : 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 [ + - ]: 160 : } else if (t == mptcp_subflow_type) {
62 [ - + ]: 160 : 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 [ - + ]: 170 : 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 : 96 : 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 : 96 : return 0;
107 : : }
108 : :
109 : 180 : 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 : 180 : const struct mptcp_sched_ops *usched;
114 : 180 : struct mptcp_sched_ops *sched;
115 : 180 : u32 moff;
116 : 180 : int ret;
117 : :
118 : 180 : usched = (const struct mptcp_sched_ops *)udata;
119 : 180 : sched = (struct mptcp_sched_ops *)kdata;
120 : :
121 [ - + ]: 180 : moff = __btf_member_bit_offset(t, member) / 8;
122 [ + + ]: 180 : 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_send(struct mptcp_sock *msk,
160 : : struct mptcp_sched_data *data)
161 : : {
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static int __bpf_mptcp_sched_get_retrans(struct mptcp_sock *msk,
166 : : struct mptcp_sched_data *data)
167 : : {
168 : 0 : return 0;
169 : : }
170 : :
171 : 0 : static void __bpf_mptcp_sched_init(struct mptcp_sock *msk)
172 : : {
173 : 0 : }
174 : :
175 : 0 : static void __bpf_mptcp_sched_release(struct mptcp_sock *msk)
176 : : {
177 : 0 : }
178 : :
179 : : static struct mptcp_sched_ops __bpf_mptcp_sched_ops = {
180 : : .get_send = __bpf_mptcp_sched_get_send,
181 : : .get_retrans = __bpf_mptcp_sched_get_retrans,
182 : : .init = __bpf_mptcp_sched_init,
183 : : .release = __bpf_mptcp_sched_release,
184 : : };
185 : :
186 : : static struct bpf_struct_ops bpf_mptcp_sched_ops = {
187 : : .verifier_ops = &bpf_mptcp_sched_verifier_ops,
188 : : .reg = bpf_mptcp_sched_reg,
189 : : .unreg = bpf_mptcp_sched_unreg,
190 : : .check_member = bpf_mptcp_sched_check_member,
191 : : .init_member = bpf_mptcp_sched_init_member,
192 : : .init = bpf_mptcp_sched_init,
193 : : .name = "mptcp_sched_ops",
194 : : .cfi_stubs = &__bpf_mptcp_sched_ops,
195 : : };
196 : : #endif /* CONFIG_BPF_JIT */
197 : :
198 : 24 : struct mptcp_sock *bpf_mptcp_sock_from_sock(struct sock *sk)
199 : : {
200 [ + - + + ]: 24 : if (unlikely(!sk || !sk_fullsock(sk)))
201 : 0 : return NULL;
202 : :
203 [ + + ]: 24 : if (sk->sk_protocol == IPPROTO_MPTCP)
204 : : return mptcp_sk(sk);
205 : :
206 [ + + + + ]: 27 : if (sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
207 [ - + ]: 18 : return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
208 : :
209 : : return NULL;
210 : : }
211 : :
212 : : BTF_SET8_START(bpf_mptcp_fmodret_ids)
213 : : BTF_ID_FLAGS(func, update_socket_protocol)
214 : : BTF_SET8_END(bpf_mptcp_fmodret_ids)
215 : :
216 : : static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
217 : : .owner = THIS_MODULE,
218 : : .set = &bpf_mptcp_fmodret_ids,
219 : : };
220 : :
221 : : struct bpf_iter_mptcp_subflow {
222 : : __u64 __opaque[2];
223 : : } __aligned(8);
224 : :
225 : : struct bpf_iter_mptcp_subflow_kern {
226 : : struct mptcp_sock *msk;
227 : : struct list_head *pos;
228 : : } __aligned(8);
229 : :
230 : : __bpf_kfunc_start_defs();
231 : :
232 : : __bpf_kfunc static struct mptcp_subflow_context *
233 : 6 : bpf_mptcp_subflow_ctx(const struct sock *sk)
234 : : {
235 [ + - + + ]: 6 : if (sk && sk_fullsock(sk) &&
236 [ + + + + ]: 9 : sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
237 : 6 : return mptcp_subflow_ctx(sk);
238 : :
239 : : return NULL;
240 : : }
241 : :
242 : : __bpf_kfunc static int
243 : 6 : bpf_iter_mptcp_subflow_new(struct bpf_iter_mptcp_subflow *it,
244 : : struct mptcp_sock *msk)
245 : : {
246 : 6 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
247 : 6 : struct sock *sk = (struct sock *)msk;
248 : :
249 : 6 : BUILD_BUG_ON(sizeof(struct bpf_iter_mptcp_subflow_kern) >
250 : : sizeof(struct bpf_iter_mptcp_subflow));
251 : 6 : BUILD_BUG_ON(__alignof__(struct bpf_iter_mptcp_subflow_kern) !=
252 : : __alignof__(struct bpf_iter_mptcp_subflow));
253 : :
254 : 6 : kit->msk = msk;
255 [ + + ]: 6 : if (!msk)
256 : : return -EINVAL;
257 : :
258 [ - + - - ]: 6 : if (!sock_owned_by_user_nocheck(sk) &&
259 [ # # ]: 0 : !spin_is_locked(&sk->sk_lock.slock))
260 : : return -EINVAL;
261 : :
262 : 6 : kit->pos = &msk->conn_list;
263 : 6 : return 0;
264 : : }
265 : :
266 : : __bpf_kfunc static struct mptcp_subflow_context *
267 : 30 : bpf_iter_mptcp_subflow_next(struct bpf_iter_mptcp_subflow *it)
268 : : {
269 : 30 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
270 : :
271 [ + - + + ]: 30 : if (!kit->msk || list_is_last(kit->pos, &kit->msk->conn_list))
272 : : return NULL;
273 : :
274 : 24 : kit->pos = kit->pos->next;
275 : 24 : return list_entry(kit->pos, struct mptcp_subflow_context, node);
276 : : }
277 : :
278 : : __bpf_kfunc static void
279 : 6 : bpf_iter_mptcp_subflow_destroy(struct bpf_iter_mptcp_subflow *it)
280 : : {
281 : 6 : }
282 : :
283 : : __bpf_kfunc static struct
284 : 6 : mptcp_sock *bpf_mptcp_sock_acquire(struct mptcp_sock *msk)
285 : : {
286 : 6 : struct sock *sk = (struct sock *)msk;
287 : :
288 [ + - - + ]: 6 : if (sk && refcount_inc_not_zero(&sk->sk_refcnt))
289 : : return msk;
290 : : return NULL;
291 : : }
292 : :
293 : 6 : __bpf_kfunc static void bpf_mptcp_sock_release(struct mptcp_sock *msk)
294 : : {
295 : 6 : struct sock *sk = (struct sock *)msk;
296 : :
297 [ + - - + ]: 6 : WARN_ON_ONCE(!sk || !refcount_dec_not_one(&sk->sk_refcnt));
298 : 6 : }
299 : :
300 : : __bpf_kfunc struct mptcp_subflow_context *
301 : 543999 : bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
302 : : {
303 [ + - ]: 543999 : if (pos >= MPTCP_SUBFLOWS_MAX)
304 : : return NULL;
305 : 543999 : return data->contexts[pos];
306 : : }
307 : :
308 : 6 : __bpf_kfunc static bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
309 : : {
310 : 6 : return tcp_rtx_queue_empty(sk);
311 : : }
312 : :
313 : : __bpf_kfunc_end_defs();
314 : :
315 : : BTF_KFUNCS_START(bpf_mptcp_common_kfunc_ids)
316 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx, KF_RET_NULL)
317 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_new, KF_ITER_NEW | KF_TRUSTED_ARGS)
318 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_next, KF_ITER_NEXT | KF_RET_NULL)
319 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_destroy, KF_ITER_DESTROY)
320 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_acquire, KF_ACQUIRE | KF_RET_NULL)
321 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_release, KF_RELEASE)
322 : : BTF_KFUNCS_END(bpf_mptcp_common_kfunc_ids)
323 : :
324 : : static const struct btf_kfunc_id_set bpf_mptcp_common_kfunc_set = {
325 : : .owner = THIS_MODULE,
326 : : .set = &bpf_mptcp_common_kfunc_ids,
327 : : };
328 : :
329 : : BTF_KFUNCS_START(bpf_mptcp_sched_kfunc_ids)
330 : : BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
331 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
332 : : BTF_ID_FLAGS(func, mptcp_subflow_active)
333 : : BTF_ID_FLAGS(func, mptcp_set_timeout)
334 : : BTF_ID_FLAGS(func, mptcp_wnd_end)
335 : : BTF_ID_FLAGS(func, tcp_stream_memory_free)
336 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
337 : : BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale, KF_SLEEPABLE)
338 : : BTF_KFUNCS_END(bpf_mptcp_sched_kfunc_ids)
339 : :
340 : : static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
341 : : .owner = THIS_MODULE,
342 : : .set = &bpf_mptcp_sched_kfunc_ids,
343 : : };
344 : :
345 : 4 : static int __init bpf_mptcp_kfunc_init(void)
346 : : {
347 : 4 : int ret;
348 : :
349 : 4 : ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
350 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCKOPT,
351 : : &bpf_mptcp_common_kfunc_set);
352 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
353 : : &bpf_mptcp_sched_kfunc_set);
354 : : #ifdef CONFIG_BPF_JIT
355 [ + - ]: 4 : ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
356 : : #endif
357 : :
358 : 4 : return ret;
359 : : }
360 : : late_initcall(bpf_mptcp_kfunc_init);
|